BaseAdapter.notifyDataSetChanged() 隐藏用户的点击
BaseAdapter.notifyDataSetChanged() hides user's clicks
我的应用程序 activity 显示通过自定义实现填充的列表视图
一个基础适配器。 Items 由一个 progressBar 和一个 CheckBox 组成。
progressBars 值由后台线程通过使用调用 BaseAdapter.notifyDataSetChanged() 的处理程序进行更新。
在此应用中,用户应该能够选中复选框。
问题是 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 的片段中。
有一个 "synchronizer":
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();
}
}
});
更新程序线程调用 synchronizer.valuesReceived() 发布一个可运行的
在 gui 线程中实例化的处理程序中:
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));
}
}
您可能点击的是列表项而不是复选框。要解决此问题
在 xml 中使复选框不可点击并处理对整个项目的检查点击。
我认为你应该考虑使用 OnCheckedChangeListener
而不是 OnClickListener
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
handler.setFailSafe((byte) inputId, isChecked);
}
});
以下是我为解决此问题所做的工作。这不是很令人满意,但它确实有效。
这个想法是对每个进度条进行手动更新,而不是使用 notifyDataSetChanged()。
在适配器中,我添加了一个 ArrayList 来存储进度条。
最后如果:
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null) {
我加了
bars.add(viewHolder.pbPosition);
为了让每个progressBar都知道自己关联的item,在
的最后
@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]);
}
}
我的应用程序 activity 显示通过自定义实现填充的列表视图 一个基础适配器。 Items 由一个 progressBar 和一个 CheckBox 组成。
progressBars 值由后台线程通过使用调用 BaseAdapter.notifyDataSetChanged() 的处理程序进行更新。 在此应用中,用户应该能够选中复选框。
问题是 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 的片段中。 有一个 "synchronizer":
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();
}
}
});
更新程序线程调用 synchronizer.valuesReceived() 发布一个可运行的 在 gui 线程中实例化的处理程序中:
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));
}
}
您可能点击的是列表项而不是复选框。要解决此问题 在 xml 中使复选框不可点击并处理对整个项目的检查点击。
我认为你应该考虑使用 OnCheckedChangeListener
而不是 OnClickListener
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
handler.setFailSafe((byte) inputId, isChecked);
}
});
以下是我为解决此问题所做的工作。这不是很令人满意,但它确实有效。 这个想法是对每个进度条进行手动更新,而不是使用 notifyDataSetChanged()。
在适配器中,我添加了一个 ArrayList 来存储进度条。 最后如果:
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null) {
我加了
bars.add(viewHolder.pbPosition);
为了让每个progressBar都知道自己关联的item,在
的最后 @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]);
}
}