使用按钮刷新列表视图会破坏onClickEvents

时间:2012-03-09 12:01:25

标签: android listview click refresh

我使用带有notifyDataSetChanged()的CursorAdapter刷新ListView。从CountDownTimer每秒调用几次通知(我显示几个倒计时器,存储在DB中)。用户界面正确更新。

问题是,我的列表视图每行有两个按钮,用于暂停/恢复和取消计时器。我在我的自定义适配器的getView()中附加了OnClickListeners(适配器本身实现了OnClickListener,我通过切换视图的ID来处理单击事件)。如果我不刷新列表视图,这可以正常工作。当我开始调用notifyDataSetChanged()时,单击事件是随机的。单击一个按钮可选择一行中的两个按钮,或选择另一行中的按钮,并且只会选择一些正确的点击事件。那些随机点击目标不可捕获(即我没有收到onClick())。

我也尝试过listView.invalidateViews(),getLoaderManager()。restartLoader(...)重新添加一个新的适配器,但都有类似的问题,甚至更糟。

我认为这可能是回收“行视图”引起的问题,但这种行为也只有一行。

问题是,如何连续刷新ListView并保留其中按钮的点击事件?

编辑适配器代码

public class TimersCursorAdapter extends SimpleCursorAdapter implements OnClickListener {

// helper interface to notify about timer has finished, so we can update the UI
public interface OnTimerFinishedLoaderReloadCallback {
    public void onTimerFinishedLoaderRestart();
}


DecimalFormat m_Format = new DecimalFormat("00");
OnTimerFinishedLoaderReloadCallback m_TimerFinishedCallback = null;

public TimersCursorAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to, int flags) {
    super(context, layout, cursor, from, to, flags);
}

public void setTimerFinishedCallback(OnTimerFinishedLoaderReloadCallback callback) {
    m_TimerFinishedCallback = callback;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = super.getView(position, convertView, parent);
    View btn;

    view.setTag(position);

    // pause
    btn = view.findViewById(R.id.timers_list_button_pause_resume);
    btn.setOnClickListener(this);

    // cancel
    btn = view.findViewById(R.id.timers_list_button_cancel);
    btn.setOnClickListener(this);

    return view;
}

@Override 
public void bindView(View view, Context context, Cursor cur) {
    String result = "00:00:00";
    long hours, minutes, seconds;

    final long now = Calendar.getInstance().getTimeInMillis() / 1000;
    long duration = cur.getLong(cur.getColumnIndex("duration"));
    final String name = cur.getString(cur.getColumnIndex("name"));

    long remaining = Math.max(0, cur.getLong(cur.getColumnIndex("start")) + duration - now);

    if (remaining > 0) {
        hours = remaining / 3600;
        remaining %= 3600;
        minutes = remaining / 60;
        remaining %= 60;
        seconds = remaining;

        result = "" + m_Format.format(hours) + ":" + m_Format.format(minutes) + ":" + m_Format.format(seconds);
    }
    else if (m_TimerFinishedCallback != null) {
        // the timer is up, so notify our listener, so the UI can be updated accordingly
        m_TimerFinishedCallback.onTimerFinishedLoaderRestart();
    }

    // remaining time
    TextView tv = (TextView)view.findViewById(R.id.timers_list_remaining_time); 
    tv.setText(result);
    tv.setTypeface(TinyTimerActivity.font);

    // timer's details
    hours = duration / 3600;
    duration %= 3600;
    minutes = duration / 60;
    duration %= 60;
    seconds = duration;

    final String details = name + " timer: " + m_Format.format(hours) + ":" + m_Format.format(minutes) + ":" + m_Format.format(seconds);  
    tv = (TextView)view.findViewById(R.id.timers_list_details);
    tv.setText(details);
}

@Override
public void onClick(View v) {
    final int position = (Integer)((ViewGroup)v.getParent()).getTag();
    final CursorWrapper cw = (CursorWrapper)getItem(position);

    switch (v.getId()) {
        case R.id.timers_list_button_cancel:
            Toast.makeText(TinyTimerActivity.AppContext, "canceling timer " + cw.getLong(cw.getColumnIndex("duration")), Toast.LENGTH_SHORT).show();
            break;

        case R.id.timers_list_button_pause_resume:
            Toast.makeText(TinyTimerActivity.AppContext, "pausing timer " + cw.getLong(cw.getColumnIndex("duration")), Toast.LENGTH_SHORT).show();
            break;
    }

}

}

编辑2: 我忘了添加,这发生在一个真正的设备上纯机器人2.3.7和4.0.0模拟器上

编辑3: 我也试图在getView中创建一个新视图,但是bahaviour是一样的。点击事件总是搞砸了。我认为唯一的解决方案是从DB填充线性布局并更新它。

public View getView(int position, View convertView, ViewGroup parent) {
    View view = m_Inflater.inflate(R.layout.timers_list_item, null);

    ViewHolder holder = new ViewHolder();
    holder.buttonCancel  = (Button)view.findViewById(R.id.timers_list_button_cancel);
    holder.buttonPause   = (Button)view.findViewById(R.id.timers_list_button_pause_resume);
    holder.textDetails   = (TextView)view.findViewById(R.id.timers_list_details);
    holder.textRemaining = (TextView)view.findViewById(R.id.timers_list_remaining_time);
    holder.buttonCancel.setOnClickListener(this);
    holder.buttonPause.setOnClickListener(this);
    holder.position = position;
    view.setTag(holder);

    // bind the view's content
    final Cursor cur = getCursor();
    cur.moveToPosition(position);
    bindView(view, mContext, cur);

    return view;
}

0 个答案:

没有答案