2

我有一个经常更新的 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 上观察到它(尽管我不确定它永远不会在那里发生)。

4

1 回答 1

0

问题是onClick()方法中的代码运行的时间与getView()执行的时间不同,所以position可能不是你所期望的......试试这个:

final String item = getItem(position);
textView.setTag(position);
textView.setText(position + " " + item);
textView.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        int position = (Integer) v.getTag();
        Log.d("Adapter", position + " " + getItem(position));
    }
});

换句话说,里面的一切new OnClickListener() { ... }都看不到里面的局部变量getView()(如positionitem),但它可以看到变量和方法(如getItem())。

于 2012-09-29T19:03:28.577 回答