使用自定义列表适配器保存和恢复 ListView
Saving and restoring ListView with Custom List Adapter
我目前正在使用 custom list adapter
并在运行时修改列表视图的行(更改文本、按钮等)。
我想找到一种方法来 save/restore 在运行时对 listview
所做的更改,当我启动另一个片段然后返回到包含列表视图的片段时。
目前每次都会重新加载列表视图,所有运行时更改都将丢失。
下面显示了我是如何设置列表适配器的。
public void setAdapterToListView(ArrayList<item> list) {
ItemList = list;
ItemAdapter adapter = new MenuItemAdapter(list, getActivity(), this);
ItemListView.setAdapter(adapter);
}
然后我使用自定义列表适配器在运行时进行更改(如上所述)。这是我如何在运行时更改内容的片段:
if (holder.qty.getText().toString().equals("Qty")) {
relativeLayout.setBackgroundColor(row.getResources().getColor(R.color.navDrawerL ightBlue));
holder.qty.setText("1");
holder.qty.startAnimation(anim);
holder.removeItem.setBackgroundResource(R.drawable.remove_item_red);
holder.removeItem.setEnabled(true);
...
是否有解决此问题的推荐方法?
适配器
您将希望您的自定义适配器为其内部数据实施某种 getter。例如
public ArrayList<YourDataType> getList() {
return new ArrayList<YourDataType>(mAdapterData);
}
Activity
然后在您的 activity/fragment 中,您需要保存和恢复该数据。
private static final String STATE_LIST = "State Adapter Data"
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(STATE_LIST, getAdapter().getList());
}
虽然有一个 onRestoreInstanceState()
方法可以覆盖,但我通常会在 onCreate()
期间恢复。通常在实例化其他事物时更方便。要么是可行的。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//If restoring from state, load the list from the bundle
if (savedInstanceState != null) {
ArrayList<YourDataType> list = savedInstanceState.getParcelableArrayList(STATE_LIST);
ItemAdapter adapter = new MenuItemAdapter(list, getActivity(), this);
} else {
//Else we are creating our Activity from scratch, pull list from where ever you initially get it from
ArrayList<YourDataType> list = getInitData();
ItemAdapter adapter = new MenuItemAdapter(list, getActivity(), this);
}
}
你的数据类型
你没有提到 YourDataType
是什么,但我假设它是一个习俗 class。为了使用捆绑的保存状态,它必须实现 Parcelable
。 Android 的开发者 link on Parcelable and a Whosebug post 解释了如何使用 Parcelable 编写您自己的自定义 class。
更新
根据您对片段所做的操作,将决定是否调用 onSavedInstanceState()
方法。从您提出问题的方式来看,我假设您将一个片段推到后台以在顶部加载另一个片段。然后点击后退按钮将从后台堆栈重新加载该片段...并传递捆绑状态以重新加载。
当然这只是众多场景中的一种。有问题的片段完全有可能只执行 onPause()
,然后执行 onStop()
...然后在重新显示该片段时,只看到它执行 onStart()
,然后执行 onResume()
。在这种情况下,不会有保存状态,因为片段从未完全销毁,所以没有什么可以恢复的。它应该处于相同的状态。如果不是,而是您看到它重新加载初始数据...那么您可能正在 onStart()
之内或之后重新加载初始数据。您需要将所有初始化数据移至 onCreate()
。
另一种可能的情况是,您完全销毁了片段,而没有将其放入后台堆栈。重新初始化它不会有可从中提取的已保存状态。如果你想"restore"这个片段回到事前的状态,那么你不能依赖onSavedInstanceState()
。您将需要手动将该信息保存在内存中的某个位置、磁盘或您自己的数据库中。然后相应地从中拉出。
不幸的是,片段的生命周期非常复杂,并且在很大程度上取决于使用情况,甚至在支持库与本机片段之间也是如此。
在做了一些 reading/research 之后,我最终通过使用 Gson (https://code.google.com/p/google-gson/) 将适配器数据保存到 Saved Preferences 解决了这个问题。
我使用 Gson 首先将我的对象数组转换为 Json,然后将 Json 字符串存储在保存的首选项中。
随后我能够根据需要检索这些并再次将 Json 读入 Java 对象,将它们存储在数组列表中并将其传递给我的列表视图适配器。
这里是对任何想做类似事情的人的流程的简要概述。
保存到共享首选项:
SharedPreferences settings;
Editor editor;
settings = c.getSharedPreferences(PREFS_NAME,Context.MODE_PRIVATE);
editor = settings.edit();
Gson gson = new Gson();
String ItemsJson = gson.toJson(list);
editor.putString(categoryId, ItemsJson);
editor.apply();
正在从共享首选项读取:
if (settings.contains(categoryId) {
String jsonItems = settings.getString(categoryId, null);
Gson gson = new Gson();
Item[] favoriteItems = gson.fromJson(jsonItems, Item[].class);
list = Arrays.asList(favoriteItems);
ItemsFromSharedPrefs = new ArrayList<>(list);
AllCategories.addAll(ItemsFromSharedPrefs);
} etc...
我目前正在使用 custom list adapter
并在运行时修改列表视图的行(更改文本、按钮等)。
我想找到一种方法来 save/restore 在运行时对 listview
所做的更改,当我启动另一个片段然后返回到包含列表视图的片段时。
目前每次都会重新加载列表视图,所有运行时更改都将丢失。
下面显示了我是如何设置列表适配器的。
public void setAdapterToListView(ArrayList<item> list) {
ItemList = list;
ItemAdapter adapter = new MenuItemAdapter(list, getActivity(), this);
ItemListView.setAdapter(adapter);
}
然后我使用自定义列表适配器在运行时进行更改(如上所述)。这是我如何在运行时更改内容的片段:
if (holder.qty.getText().toString().equals("Qty")) {
relativeLayout.setBackgroundColor(row.getResources().getColor(R.color.navDrawerL ightBlue));
holder.qty.setText("1");
holder.qty.startAnimation(anim);
holder.removeItem.setBackgroundResource(R.drawable.remove_item_red);
holder.removeItem.setEnabled(true);
...
是否有解决此问题的推荐方法?
适配器
您将希望您的自定义适配器为其内部数据实施某种 getter。例如
public ArrayList<YourDataType> getList() {
return new ArrayList<YourDataType>(mAdapterData);
}
Activity
然后在您的 activity/fragment 中,您需要保存和恢复该数据。
private static final String STATE_LIST = "State Adapter Data"
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(STATE_LIST, getAdapter().getList());
}
虽然有一个 onRestoreInstanceState()
方法可以覆盖,但我通常会在 onCreate()
期间恢复。通常在实例化其他事物时更方便。要么是可行的。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//If restoring from state, load the list from the bundle
if (savedInstanceState != null) {
ArrayList<YourDataType> list = savedInstanceState.getParcelableArrayList(STATE_LIST);
ItemAdapter adapter = new MenuItemAdapter(list, getActivity(), this);
} else {
//Else we are creating our Activity from scratch, pull list from where ever you initially get it from
ArrayList<YourDataType> list = getInitData();
ItemAdapter adapter = new MenuItemAdapter(list, getActivity(), this);
}
}
你的数据类型
你没有提到 YourDataType
是什么,但我假设它是一个习俗 class。为了使用捆绑的保存状态,它必须实现 Parcelable
。 Android 的开发者 link on Parcelable and a Whosebug post 解释了如何使用 Parcelable 编写您自己的自定义 class。
更新
根据您对片段所做的操作,将决定是否调用 onSavedInstanceState()
方法。从您提出问题的方式来看,我假设您将一个片段推到后台以在顶部加载另一个片段。然后点击后退按钮将从后台堆栈重新加载该片段...并传递捆绑状态以重新加载。
当然这只是众多场景中的一种。有问题的片段完全有可能只执行 onPause()
,然后执行 onStop()
...然后在重新显示该片段时,只看到它执行 onStart()
,然后执行 onResume()
。在这种情况下,不会有保存状态,因为片段从未完全销毁,所以没有什么可以恢复的。它应该处于相同的状态。如果不是,而是您看到它重新加载初始数据...那么您可能正在 onStart()
之内或之后重新加载初始数据。您需要将所有初始化数据移至 onCreate()
。
另一种可能的情况是,您完全销毁了片段,而没有将其放入后台堆栈。重新初始化它不会有可从中提取的已保存状态。如果你想"restore"这个片段回到事前的状态,那么你不能依赖onSavedInstanceState()
。您将需要手动将该信息保存在内存中的某个位置、磁盘或您自己的数据库中。然后相应地从中拉出。
不幸的是,片段的生命周期非常复杂,并且在很大程度上取决于使用情况,甚至在支持库与本机片段之间也是如此。
在做了一些 reading/research 之后,我最终通过使用 Gson (https://code.google.com/p/google-gson/) 将适配器数据保存到 Saved Preferences 解决了这个问题。
我使用 Gson 首先将我的对象数组转换为 Json,然后将 Json 字符串存储在保存的首选项中。
随后我能够根据需要检索这些并再次将 Json 读入 Java 对象,将它们存储在数组列表中并将其传递给我的列表视图适配器。
这里是对任何想做类似事情的人的流程的简要概述。
保存到共享首选项:
SharedPreferences settings;
Editor editor;
settings = c.getSharedPreferences(PREFS_NAME,Context.MODE_PRIVATE);
editor = settings.edit();
Gson gson = new Gson();
String ItemsJson = gson.toJson(list);
editor.putString(categoryId, ItemsJson);
editor.apply();
正在从共享首选项读取:
if (settings.contains(categoryId) {
String jsonItems = settings.getString(categoryId, null);
Gson gson = new Gson();
Item[] favoriteItems = gson.fromJson(jsonItems, Item[].class);
list = Arrays.asList(favoriteItems);
ItemsFromSharedPrefs = new ArrayList<>(list);
AllCategories.addAll(ItemsFromSharedPrefs);
} etc...