当用户旋转手机并保留ArrayAdapter中的所有数据时,保留listview项目的良好解决方案

bar*_*ian 41 android android-listview android-fragments

我正在使用Fragment和listView.我通过自定义Loader(来自互联网)收到的数据填充与此列表视图关联的ArrayAdapter.Custom ArrayAdapter支持无限滚动(分页).

当用户在ListView中旋转设备并保持滚动位置时,在ArrayAdapter中存储项目的最佳方法是什么?

我正在考虑使用ArrayAdapter创建非可视片段,并使用setRetainInstance方法来保存值.

有什么更好的解决方案吗?

Phi*_*hil 56

要使用Android框架和Fragment生命周期,您应该onSaveInstanceState在Fragment中实现该方法.为简单起见,我假设您有一个可以获得的String值数组(我通常扩展ArrayAdapter以封装视图构造并提供访问整个底层数据集的便捷方法):

public void onSaveInstanceState(Bundle savedState) {

    super.onSaveInstanceState(savedState);

    // Note: getValues() is a method in your ArrayAdapter subclass
    String[] values = mAdapter.getValues(); 
    savedState.putStringArray("myKey", values);

}
Run Code Online (Sandbox Code Playgroud)

然后,您可以在onCreate方法(或onCreateView或onActivityCreated - 请参阅Fragment JavaDoc)中检索数据,如下所示:

public void onCreate (Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    if (savedInstanceState != null) {
        String[] values = savedInstanceState.getStringArray("myKey");
        if (values != null) {
           mAdapter = new MyAdapter(values);
        }
    }

    ...

}
Run Code Online (Sandbox Code Playgroud)

这可确保正确处理所有生命周期事件,而不会丢失数据,包括设备轮换和用户切换到其他应用程序.不使用onSaveInstanceState和使用内存的危险是Android回收内存的危险.保存的状态不会受此影响,但使用实例变量或隐藏的片段会导致数据丢失.

如果savedStateInstance为null,则没有要恢复的状态.

if (values != null)只是为了防止没有保存数组的可能性,但如果您编写ArrayAdapter来处理空数据集,则不需要这样做.

如果您的行是您自己的类之一而不是单个数据项的实例,那么最终的解决方案是在该类上实现Parcelable接口,然后您可以使用savedState.putParcelableArray("myKey", myArray).你会惊讶于知道如何实现Parcelable是多么有用 - 它允许你在内部传递你的类,并允许你编写更清晰的代码.

  • 要保留滚动位置,还要在onSaveInstanceState()中保存:listView.getFirstVisiblePosition().将适配器设置为listView后,只需添加以下行:listView.setSelectionFromTop(index,0); 索引是您保存的索引. (19认同)
  • @vickey:好评,正是我想要的. (3认同)
  • 如果我们不使用数组适配器而是使用baseAdapter,而是将Object的数组列表传递给适配器构造函数,该怎么办? (2认同)

Vik*_*pta 6

旋转设备后,应用程序将重新启动.因此onSaveInstance在应用程序被销毁之前调用.您可以保存数组适配器,onSaveInstance并在onCreate再次启动应用程序时最终调用该数组适配器,您可以检索数组适配器并将其设置为列表视图.

  • 你不对,只重建前景Activity. (5认同)

She*_*tib 5

保存适配器的项目非常容易onSaveInstance.

现在您需要保存位置(滚动).你可以这样做

简单的方法

因为改变screenOrientation会使事情变得混乱,你可以允许一些边际错误,简单地说,在你的情况下onSaveInstance,使用保存第一个可见项目listView.getFirstVisiblePosition().

然后在您onRestoreInstance可以检索此索引以使用滚动到相同的项目listview.setSelection(position).当然,你可以使用,listview.smoothScrollToPosition(position)但那会很奇怪.


困难的方式

要获得更准确的位置,您需要再向下1级:获取滚动位置(而不是索引)并保存该位置.然后在恢复后,滚动回到此位置.在你的onSaveInstance,保存从中返回的位置listview.getScrollY().当您在自己中检索此位置时onRestoreInstance,可以使用滚动回到此位置listview.scrollTo(0, position).


为什么这真的很难?

简单.您很可能无法回滚到此位置,因为您的列表视图尚未通过测量和布局.您可以通过在使用设置适配器后等待布局来克服此问题getViewObserver().addOnGlobalLayoutListener.在此回调中,发布runnable以滚动到该位置.


我建议使用第一种"简单方法",因为一般来说,当屏幕方向改变时,用户可能会将手指向后移动.我们只需向他展示"给予或接受"的相同项目.