【问题标题】:Saving and restoring ListView with Custom List Adapter使用自定义列表适配器保存和恢复 ListView
【发布时间】:2015-03-23 00:24:48
【问题描述】:

我目前正在使用custom list adapter 并在运行时修改列表视图的行(更改文本、按钮等)。

当我启动另一个片段然后返回到包含列表视图的片段时,我想找到一种方法来保存/恢复在运行时对listview 所做的更改。

目前每次都会重新加载列表视图,并且所有运行时更改都会丢失。

下面显示了我是如何设置列表适配器的。

 public void setAdapterToListView(ArrayList<item> list) {
        ItemList = list;
        ItemAdapter adapter = new MenuItemAdapter(list, getActivity(), this);
        ItemListView.setAdapter(adapter);
    }

然后我使用自定义列表适配器在运行时进行更改(如上所述)。这是我如何在运行时更改内容的 sn-p:

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);

   ...

有没有推荐的方法来解决这个问题?

【问题讨论】:

  • 查看如何使用保存和恢复实例状态。它是 Activity 和 Fragment 生命周期的一部分,可以在官方 android API 参考中找到。请参阅:developer.android.com/training/basics/activity-lifecycle/…(这是针对 Activity,但也适用于 Fragments)
  • 我可能不明白你的问题。您正在使用自定义适配器,但这与您如何保存 Listview 数据无关。您可以简单地将 ArrayList 保存在缓存中直到应用程序退出吗?或者您是否需要一个用于 Listview 数据的数据库以在应用退出后保存它们?
  • @TheOriginalAndroid 我正在从服务器检索列表视图的数据,所以这不是问题。用户可以通过单击按钮等方式修改此列表视图。它本质上是一个购物车。我想确保对列表视图的这些修改被保存并且可以恢复。是否可以保留整个列表视图的状态?
  • 我认为的主要状态是Listview的行位置和排序顺序。但是,如果您想要更广泛的内容,请查看 Serializable,developer.android.com/reference/java/io/Serializable.html。如果您选择此设计,请使用 Serializable 标记您的问题。
  • 你能发布你的适配器代码吗?或者至少是显示您如何跟踪对适配器中的文本、按钮等的修改的相关代码。

标签: android listview android-fragments android-listview


【解决方案1】:

适配器

您会希望您的自定义适配器为其内部数据实现某种 getter。比如

public ArrayList<YourDataType> getList() {
    return new ArrayList<YourDataType>(mAdapterData);
}

活动

然后在您的活动/片段中,您需要保存和恢复该数据。

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 是什么,但我假设它是一个自定义类。为了使用捆绑的已保存状态,它必须实现Parcelable。 Android 的开发者 link 在 Parcelable 和 StackOverFlow post 解释如何使用 Parcelable 编写您自己的自定义类。

更新

根据您对片段所做的操作,将决定是否调用 onSavedInstanceState() 方法。从您提出问题的方式来看,我假设您正在将一个片段推入后台堆栈以将另一个片段加载到顶部。然后点击后退按钮将从后台堆栈重新加载该片段......并传递捆绑状态以重新加载。

当然,这只是众多场景之一。有问题的片段完全有可能只执行onPause(),然后是onStop()...然后在重新显示片段时,只看到它执行onStart(),然后是onResume()。在这种情况下,不会有保存状态,因为片段从未被完全销毁,所以没有什么可恢复的。它应该处于相同的状态。如果不是,而是您看到它重新加载初始数据……那么您可能正在onStart() 中或之后重新加载初始数据。您需要将所有初始化数据移至 onCreate()

另一种可能的情况是您完全销毁片段而没有将其放入后台堆栈。重新初始化它不会有保存状态可供提取。如果你想把这个片段“恢复”到事先的状态,那么你不能依赖onSavedInstanceState()。您需要手动将该信息保存在内存中的某个位置、磁盘或数据库中。然后相应地从中拉出。

不幸的是,片段的生命周期非常复杂,并且很大程度上取决于使用情况,甚至在支持库与原生片段之间也是如此。

【讨论】:

  • 非常感谢您提出的解决方案 Jay。我尝试实现这一点,但注意到当我“退出”包含 ListView 的片段时,没有调用 onSaveInstanceStateonPause()onStop() 被调用。出于这个原因,我无法将 Parcleable 保存到 Bundle 中。在做了一些阅读之后,有人提到 onSaveInstanceState 不是片段生命周期的一部分,因此在需要时可能不会调用它。如果是这种情况,是否可以实现使用 onPause() 的解决方法?
  • 作为附录,这里有一些关于这个问题的好信息:stackoverflow.com/questions/15935322/…
  • 感谢您的更新。我做了一些进一步的研究,并按照你的建议寻找一种方法来保存信息。结果证明它比管理片段状态更容易。干杯!
  • 请注意最新的 android 限制为 parcelable 1mb
【解决方案2】:

在做了一些阅读/研究之后,我最终通过使用 Gson (https://code.google.com/p/google-gson/) 将适配器数据保存到 Saved Preferences 来解决这个问题。

我使用 Gson 首先将我的对象数组转换为 Json,然后将 Json 字符串存储在 Saved Preferences 中。

随后,我能够根据需要检索这些并再次将 Json 读入 Java 对象,将它们存储在数组列表中并将其传递给我的 listview 适配器。

以下是对任何想要做类似事情的人的流程的简要概述。

保存到共享首选项:

    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...

【讨论】:

  • 即使列表是 500 项,这是否也能正常运行?
猜你喜欢
  • 2014-05-20
  • 1970-01-01
  • 2016-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多