【问题标题】:ArrayAdapter with Filter crashes带有过滤器的 ArrayAdapter 崩溃
【发布时间】:2014-06-27 17:47:42
【问题描述】:

我有自己的ArrayAdapter,在这个适配器类里面我有一个Filter。在这个过滤器中,我覆盖了publishResults(CharSequence constraint, FilterResults result) 方法。

@Override
        protected void publishResults(CharSequence constraint, FilterResults result) {
final ArrayList<Car> filtered = (ArrayList<Car>) results.values;
for (int i = 0, l = filtered.size(); i < l; i++) {
                add(filtered.get(i));


            }
}

当我只有 100 个左右的条目时,上面的方法可以正常工作。当我的条目达到数千时,UI 线程会挂起几秒钟。我以为我会把它移到AsyncTask,但它崩溃了。在不挂起 UI 的情况下处理我的结果的最佳方法是什么?

崩溃的代码(似乎开始,并在 for 循环中间崩溃:

@Override
        protected void publishResults(CharSequence constraint, FilterResults result) {
final ArrayList<Car> filtered = (ArrayList<Car>) results.values;
new LongOperation().execute(filtered);
}

    private class LongOperation extends AsyncTask<ArrayList<Car>, Void, Void> {

        @Override
        protected Void doInBackground(ArrayList<Car>... params) {
            for (int i = 0, l = params[0].size(); i < l; i++) {
                add(params[0].get(i));


            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            notifyDataSetChanged();
        }
    }
};

这是崩溃消息。我正在使用 commonsware MergeAdapter 来组合两个适配器,所以这可能是问题所在?

E/AndroidRuntime(22868): java.lang.IllegalStateException: 
    The content of the adapter has changed but ListView did not receive a notification.
    Make sure the content of your adapter is not modified from a background thread, 
    but only from the UI thread. Make sure your adapter calls notifyDataSetChanged()
    when its content changes. [in ListView(16908298, class android.widget.ListView) 
    with Adapter(class com.commonsware.cwac.merge.MergeAdapter)]

【问题讨论】:

  • 您似乎正在从doInBackground() 调用add() 方法。这是在做什么?
  • add() iscomingFrom ArrayAdapter - "在数组末尾添加指定的对象。"

标签: android android-asynctask android-arrayadapter android-adapter commonsware-cwac


【解决方案1】:

您不能在后台线程中操作适配器数据。这就是错误所说的:

确保您的适配器的内容没有从 后台线程,但只能来自 UI 线程

一种解决方案可能是让数据有两种表示形式,当它发生变化时,只需在它们之间交换即可。并确保您在主线程上进行交换。

【讨论】:

  • 同意。不要在后台线程中的ArrayAdapter 上调用add(),例如从AsyncTaskdoInBackground()
  • 所以我已经将数据作为 ArrayList 变量“过滤”了。我可以设置整个 ArrayAdapter 来代替它吗?我不确定您所说的“数据的两种表示形式”是什么意思
  • @EGHDK 是的,只要您在主线程上执行此操作,并且稍后不要在其他线程(例如从 AsynTask 中)操作它。
  • 我应该在 publishResults() 方法中将 ArrayAdapter 设置为新的 ArrayList 吗?
  • @CommonsWare 我现在明白调用 add 也会执行一个 notifydatasetchanged ,这应该发生在 UI 线程上。我不明白伊利亚提供的答案。我意识到这是一个解释,但我不确定在这种情况下我将如何实现类似的东西。我会在 publishResults() 中将数据集(过滤后的)交换到当前的数组列表中吗?
猜你喜欢
  • 1970-01-01
  • 2018-11-18
  • 2020-11-05
  • 2012-04-24
  • 2023-04-05
  • 2019-03-08
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多