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;
}
}
~~~