我有一个经常更新的 Android ListView。当我单击列表中的某个项目时,错误对象获得单击事件的时间的某个子集。即使更新没有更改列表,也会发生这种情况。
我只是编码错误,还是通过视图层次结构处理事件时存在竞争条件?
ListView 使用扩展 BaseAdapter 的适配器,其 getView() 方法如下所示。但是这个问题只出现在USE_LAYOUT=true的时候。
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view;
TextView textView;
ViewHolder viewHolder;
if (convertView == null) {
if (USE_LAYOUT) {
view = context.getLayoutInflater().inflate(R.layout.row, parent, false);
textView = (TextView) view.findViewById(R.id.rowTextView);
} else {
view = new TextView(context);
textView = (TextView) view;
}
viewHolder = new ViewHolder();
viewHolder.textView = textView;
view.setTag(viewHolder);
} else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
textView = viewHolder.textView;
}
final String item = getItem(position);
textView.setText(position + " " + item);
textView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Adapter", position + " " + item);
}
});
return view;
}
所以就上面的代码而言,活动显示一个列表视图,显示“1 item1”、“2 item2”、“3 item3”等。如果我点击 item3,有一定比例的时间,日志将显示“21 项 21”。
关于代码的其他几点:
- 该项目只是一个字符串,适配器维护一个
List<String>
,getItem()
只是调用items.get(index)
,并setItems()
设置列表和调用notifyDataSetChanged()
。 - 如果列表未更改,则会出现此问题。即,计时器调用
setItems(new ArrayList<String>(getItems())
. setItems()
从 UI 线程通过runOnUiThread()
.- 计时器每 500 毫秒左右关闭一次,但其他频率也会出现问题。
- 行布局只是 LinearLayout 中的 TextView。
我观察到,当通过 getView 回收视图时,它们会以相反的顺序回收。换句话说,当notifyDataSetChanged()
被调用并且列表没有滚动时,第一个项目与最后一个项目一起回收,第二个项目与倒数第二个项目一起回收,等等。因此我怀疑竞争条件。此外,我在 2.1 和 2.3 上观察到它,但不是在 4.0 上观察到它(尽管我不确定它永远不会在那里发生)。