我正在使用ListView和2个线程调试Android应用程序 - 一个更新数据存储区的工作线程和执行所有常见View内容的主UI线程,包括显示列表视图。 (这应该是一个快速调试,所以我没有被要求改变这个架构)。我发现存在线程冲突,因为当 getView()尝试使用数据存储区中的东西时,工作线程有时会运行。
因此,为了防止这些冲突,我创建一个计数为1的信号量,工作线程必须在触摸数据存储阵列之前获取它。我还覆盖 notifyDataSetChanged()并在其中放置一个获取和释放以及一些日志记录来检测它。
@Override
public void notifyDataSetChanged() {
try {
MyActivity.datastoreSemaphore.acquire();
Log.d ("notifyDataSetChanged()...", " acquired semaphore " );
try {
super.notifyDataSetChanged();
Log.d ("notifyDataSetChanged()...", "listItems.size()=" + String.valueOf(listItems.size()) + " lv.getCount()=" + String.valueOf(lv.getCount()) ); //!! debugging
} catch (Exception e) {
Log.e ("notifyDataSetChanged() inner catch ", "Exception = " + e ); debugging
} finally {
MyActivity.datastoreSemaphore.release();
Log.d ("notifyDataSetChanged()...", " released semaphore " );
}
} catch (InterruptedException e) {
Log.e ("notifyDataSetChanged() outer catch ", "Exception = " + e );
}
}
我还检测了 getView()和这里是我得不到的东西:跟踪显示 getView()被称为OUTSIDE的时候 notifyDataSetChanged()被调用.. 。
05-25 13:36:37.865:D / notifyDataSetChanged()...(21863):获得 信号量05-25 13:36:37.865:D / notifyDataSetChanged()...(21863): listItems.size()= 14 lv.getCount()= 14
05-25 13:36:37.865:D / notifyDataSetChanged()...(21863):已发布 信号量
05-25 13:36:37.869:D /进入getView()...(21863):position = 0 适配器的getCount()= 14
05-25 13:36:37.873:D / in getView()...(21863):listItems size = 14 position = 0
05-25 13:36:37.873:D /退出getView()...(21863):position = 0 适配器的getCount()= 14
05-25 13:36:37.873:D /进入getView()...(21863):position = 1 适配器的getCount()= 14
05-25 13:36:37.873:D / in getView()...(21863):listItems size = 14 position = 1
换句话说,根据LogCat,我们调用 notifyDataSetChanged();我们获取信号量,调用基本方法,从基本方法返回,释放信号量,那么 getView()循环启动。 。
我的印象是 notifyDataSetChanged()在整个 getView()循环事件完成之前不会返回,但这似乎不是这样。这里发生了什么事? ( NB ,这个问题并不是关于信号量或线程collsions - 我提到那些提供上下文 - 问题是关于 getView()循环WRT的时间 notifyDataSetChanged()。)
编辑:对 notifyDataSetChanged()的调用通过runOnUIThread()中的runnable在主UI线程上运行。在屏幕上的跟踪中,所有适配器内容的TID都显示为主UI线程。我会更新问题以反映这一点。
答案 0 :(得分:0)
notifyDataSetChanged()
仅在其关联的观察者上触发onChanged()
方法。
对于AdapterView
子类(例如ListView
),最终会调用requestLayout()
schedules a layout pass of the view tree。
因此,简而言之,它不是即时的。最终,将为每个项目调用getView()
,但在notifyDataSetChanged()
完成之前不会。{/ p>
无论如何,从工作线程调用notifyDataSetChanged()
不是一个好主意。实际上,从后台线程修改适配器的内容可能会产生异常。消息通常是:
适配器的内容已更改,但ListView未收到 通知。确保未修改适配器的内容 来自后台线程,但仅来自UI线程。确保你的 适配器在其内容发生变化时调用notifyDataSetChanged()。