BaseAdapter.notifyDataSetChanged()隐藏用户的点击次数

时间:2016-11-21 10:35:50

标签: android onclicklistener notifydatasetchanged

我的应用活动显示通过自定义实现填充的列表视图 一个BaseAdapter。项目由progressBar和CheckBox组成。

progressBars值由后台线程通过使用调用BaseAdapter.notifyDataSetChanged()的Handler更新。 在这个应用程序中,用户应该能够检查复选框。

问题是似乎notifyDataSetChanged()隐藏或忽略用户对CheckBox的点击。 会发生的是onClickListener.onClick()被称为用户点击的1/5倍。

一开始,我认为BaseAdapter.getView()设置的值会覆盖用户点击CheckBox所设置的任何值。所以我在getView()中尝试过类似的东西:

if (checkBox.isChecked != data.isChecked(){
    checkBox.setOnCheckedChangeListener(null);
    checkBox.setChecked(data.isChecked());
    checkBox.setOnCheckedChangeListener(cbClickListener);
}

没有任何变化,在onClickListener.onClick()中添加日志已经清楚地表明每次都不会调用onClick。 我该怎么办?

这是非常经典的适配器代码:

class InputsConfAdapter extends BaseAdapter {
    private static LayoutInflater inflater = null;
    private final Model model;
    private final inputsConfAdapterInterface handler;
    private int[] positions;

    //---------------------------------------------------------------------------------------------------

    class CbClickListener implements CheckBox.OnCheckedChangeListener{

        int inputId;

        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            handler.setFailSafe((byte) inputId, isChecked);
       }
    }
    //---------------------------------------------------------------------------------------------------

    public InputsConfAdapter(LayoutInflater inflater, Model model, inputsConfAdapterInterface handler) {
        super();
        InputsConfAdapter.inflater = inflater;
        this.handler = handler;
        this.model = model;
    }

    @Override
    public int getCount() {
        return model.inputs.length;
    }

    @Override
    public Object getItem(int i) {
        return i;
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        if (view == null) {
            view = inflater.inflate(R.layout.theIem, null);
            ViewHolder viewHolder = new ViewHolder();
            viewHolder.pbPosition = (ProgressBar) view.findViewById(R.id.pbPosition);
            viewHolder.checkBox = (CheckBox) view.findViewById(R.id.cb);

            final CbClickListener cbClickListener = new CbClickListener();
            viewHolder.checkBox.setOnCheckedChangeListener(cbClickListener);
            viewHolder.cbClickListener = new CbClickListener();

            view.setTag(viewHolder);
        }

        final ViewHolder viewHolder = (ViewHolder) view.getTag();
        final CheckBox checkBox = viewHolder.checkBox;
        final ProgressBar pbPosition = viewHolder.pbPosition;
        final CbClickListener cbClickListener = viewHolder.cbClickListener;

        final Input data = model.inputs[i];

//--- progressBar
        if (positions != null)
            pbPosition.setProgress(positions[i]);

//--- checkBox
        cbClickListener.inputId = i;
        checkBox.setOnCheckedChangeListener(null);
        checkBox.setChecked(data.isChecked());
        checkBox.setOnCheckedChangeListener(cbClickListener);
        return view;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public int getViewTypeCount() {
        return 1;
    }

    public void serPositions(int[] positions) {
        this.positions = positions;
    }

    private class ViewHolder {
        public CheckBox checkBox;
        public ProgressBar pbPosition;
        CbClickListener cbClickListener;

        public ViewHolder() {

        }
    }

    public interface inputsConfAdapterInterface {
        void setFailSafe(byte inputId, boolean value);
    }
}

@Khaled的更新:在接收listView的片段中。 有一个“同步器”:

  private final Synchronizer synchronizer = new Synchronizer(new Handler(), new DefaultListener() {
        @Override
        public void ValuesReceived(ValueStruct values) {
            if (getActivity() != null) {
                adapter.serPositions(values.values);
                adapter.notifyDataSetChanged();
            }
        }
    });

updater线程调用synchronizer.valuesReceived(),它发布了一个runnable 在gui线程中实现的Handler:

public interface ISink {
    void ValueReceived(
        ValueStruct inputValue
    );
}


public class defaultListener implements ISink {
}


public class Synchronizer implements ISink {
    private ISink sink;
    private Handler handler;

    public Synchronizer(Handler handler, ISink sink) {
        this.handler = handler;
        this.sink = sink;
    }

    private class ValueRunnable implements Runnable {
        ValueStruct s;

        ValueRunnable(ValueStruct s) {
            this.s = new ValueStruct(s);
        }

        @Override
        public void run() {
            sink.ValuesReceived(s);
        }
    }

    @Override
    public void ValuesReceived(ValueStruct s) {
        handler.post(new ValueRunnable(s));
    }
}

3 个答案:

答案 0 :(得分:0)

您可能正在点击列表项而不是复选框。要解决此问题 使复选框在xml中无法点击并处理检查点击整个项目。

答案 1 :(得分:0)

我认为您应该考虑使用OnCheckedChangeListener代替OnClickListener

    checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
            handler.setFailSafe((byte) inputId, isChecked);
        }
    });

答案 2 :(得分:0)

这是我为解决这个问题所做的工作。它不是很令人满意,但它确实有效。 我们的想法是使用notifyDataSetChanged()来手动更新每个进度条。

在adapater中,我添加了一个ArrayList来存储progressbars。 在此结束时:

 public View getView(int i, View view, ViewGroup viewGroup) {
        if (view == null) {

我添加了

bars.add(viewHolder.pbPosition);

为了使每个progressBar在

结尾处知道与之相关的项目
 @Override
    public View getView(int i, View view, ViewGroup viewGroup) {

我添加了

pbPosition.setTag(i);

我删除了对adapter.notifyDataSetChanged();

的调用

我将setPositions(...)更改为

public void serPositions(int[] positions) {
    for (ProgressBar bar :
            bars) {
        int index = (int) bar.getTag();
        bar.setProgress(positions[index]);
    }
}