ListView优化以及checkbox状态问题

最后更新于:2022-04-01 14:43:34

ListView优化问题网上已经有很多资料了,下面只是简单贴一个demo。这里要说一下listview里面checkbox的状态问题。 ~~~ holder.cb_vd.setChecked(state.get(position));          holder.tv_vd.setText(processList.get(position).processName);                    holder.cb_vd                  .setOnCheckedChangeListener(new OnCheckedChangeListener() {                      @Override                      public void onCheckedChanged(CompoundButton buttonView,                              boolean isChecked) {                          // TODO Auto-generated method stub                          if (isChecked) {                              state.put(position, true);                          } else {                              state.put(position, false);                              System.out.println(position+" :"+state.get(position));                          }                                                }                  }); ~~~ 通过这段代码进行注册checkbox的监听器,并且进行状态监听发现:当listview每一个item滑出屏幕的时候,上面这个函数都会被调用,并且isCheckde都会设为false!觉得非常的不可思议。然后自己查找了很久资料,发现是上面的话调错位置了。应该是这样写的: ~~~ holder.cb_vd .setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // TODO Auto-generated method stub if (isChecked) { state.put(position, true); } else { state.put(position, false); System.out.println(position); } } }); holder.cb_vd.setChecked(state.get(position)); holder.tv_vd.setText(processList.get(position).processName); ~~~ 至于原因的话,下面这段话表达的非常的好! 起因还是得讲到ListView的回收机制。假如我的ListView最多只能显示10个View,那么起初就会调用十次getView构造十个全新的View(包括对其中的checkbox设置监听器)。当我将列表往下拉出现第11个列表项的时候,顶部第一个列表项被隐藏,同样会再调用一次getView,不过此时getView的参数将返回刚刚被隐藏的第一个列表项的View,并对这个View更改数据作为即将出现的第11个View。问题就出在这里,我把checkbox.setChecked()方法调用放在了设置监听器前面,此时因为更改了checkbox的状态,势必引起触发状态更改的监听器。注意!由于第11个View是用被隐藏的第1个View回收来的,虽然还没有执行下一行设置监听器的代码,但实际上它已经拥有了一个状态监听器,这个监听器是这个View还是作为第一个View时设置。那个时候的监听器设置更改的第一项的数据,而不是第11项数据。因此,理所当然不能正确更改第11项数据,反而更改了无辜的第1项数据。如果我把两行代码顺序反过来,先更改监听器,再设置状态,引发的监听器自然也就是新的监听器,逻辑也就对了。 (转自 http://www.jb51.net/article/33424.htm) 下面贴上全部代码: ~~~ package com.example.mytesttwo; import java.util.Hashtable; import java.util.List; import android.os.Bundle; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends Activity { private ListView lv; private List<RunningAppProcessInfo> processList; private Hashtable<Integer, Boolean> state; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); state = new Hashtable<Integer, Boolean>(); lv = (ListView) findViewById(R.id.lv); ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); processList = am.getRunningAppProcesses(); lv.setAdapter(new MyAdapter()); } private class MyAdapter extends BaseAdapter { @Override public int getCount() { // TODO Auto-generated method stub return processList.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return null; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return 0; } @Override public View getView(final int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub ViewHolder holder = null; if (convertView == null) { convertView = View.inflate(MainActivity.this, R.layout.iv_item, null); holder = new ViewHolder(); holder.tv_vd = (TextView) convertView .findViewById(R.id.process_name); holder.cb_vd = (CheckBox) convertView.findViewById(R.id.chose); convertView.setTag(holder); state.put(position, false); } else { holder = (ViewHolder) convertView.getTag(); if (state.get(position) == null) { state.put(position, false); } } holder.cb_vd .setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // TODO Auto-generated method stub if (isChecked) { state.put(position, true); } else { state.put(position, false); System.out.println(position); } } }); holder.cb_vd.setChecked(state.get(position)); holder.tv_vd.setText(processList.get(position).processName); return convertView; } } private class ViewHolder { public TextView tv_vd; public CheckBox cb_vd; } } ~~~
';