【问题标题】:ListFragment IllegalStateException: "The content of the adapter has changed but ListView did not receive the notification"ListFragment IllegalStateException:“适配器的内容已更改,但 ListView 没有收到通知”
【发布时间】:2014-12-26 12:32:41
【问题描述】:

我阅读了一些答案,但我不知道如何将解决方案应用于我的问题。

为了说明问题何时发生,我有一个 ViewPager,其中有 3 个选项卡,每个选项卡对应一个片段。第一个片段有一个 ListView。当我在其他两个选项卡之间快速滑动时,我的应用程序崩溃并出现此错误。我了解我的 Fragment 会继续重新加载以及发生的位置。我不确定如何解决它。

有问题的代码:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    feed = getListView();

    feedItems = new ArrayList<FeedItem>();
    listAdapter = new FeedListAdapter(getActivity(), feedItems);
    feed.setAdapter(listAdapter);

    new Thread(new Runnable() {
        public void run() {
            for (int i = 0; i < 9; i++) {
                FeedItem item = new FeedItem("Status " + i);

                feedItems.add(item);
           }

           getActivity().runOnUiThread(new Runnable() {
               public void run() {
                   listAdapter.notifyDataSetChanged();
               }
           }
        }
    }).start();
}

关于 Stack Overflow 如何在不同线程之间拆分事物(在工作线程上处理,然后在 UI 线程上通知或执行 UI 更改),上面的代码是一本非常教科书。

这里的罪魁祸首是feedItems.add(item);

我已经阅读了有关在 UI 线程中将项目添加到 ArrayList 的信息,但如果我一次添加一个,感觉好像我会在后台线程和 UI 线程之间来回弹跳对于循环的每次迭代。一个快速的解决方案是简单地拥有两个 ArrayList,一个我在 for 循环中使用,一个最终由适配器使用,当我基本上将一个 ArrayList 复制到另一个然后listAdapter.notifyDataSetChanged();

我不能说我特别喜欢上述解决方案。似乎有点俗气。从本质上讲,这感觉像是一个多线程问题,我根本不想通过在通知适配器更改之前将 ArrayList 复制到另一个来备份 UI 线程。就个人而言,我认为我需要在某个地方进行一些同步,但我对此并不陌生,不知道如何进行设置。

我认为,一个答案会非常清楚,并且对许多遇到此问题的其他人也非常有益。

【问题讨论】:

    标签: java android multithreading android-fragments illegalstateexception


    【解决方案1】:

    您需要在runOnUiThread() 方法中更新您的用户界面。因此,只需在该方法中设置您的适配器即可。

    所以你的最终代码将是。

     getActivity().runOnUiThread(new Runnable() {
               public void run() {
                   listAdapter = new FeedListAdapter(getActivity(), feedItems);
                   feed.setAdapter(listAdapter);
                   listAdapter.notifyDataSetChanged();
               }
     }
    

    【讨论】:

    • 这是在 UI 线程上设置的。它位于new Thread(new Runnable() { 线上方。
    • 没有。您无需在该行上方写字。您的列表视图将在runOnUiThread 方法中更新。因此只需在runOnUiThread 方法中的列表视图中设置适配器,而不是编写new Thread(new Runnable() { 行。
    • 好的,好消息是它解决了这个问题。我不明白为什么这解决了这个问题。
    • 是的,进行您建议的更改消除了错误。我不明白为什么。
    • 这是因为您的UI 无法在主线程中更新。所以你需要在runOnUiThread() 方法中更新,当你使用AsyncTask 时,你的UI 将在onPostExecute() 方法中更新。
    猜你喜欢
    • 2011-09-22
    • 2011-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多