为什么要重写getView方法 可以看这里 android listView滚动时checkBox的状态不会保存的问题
拿出 android listView滚动时checkBox的状态不会保存的问题 这里的getView方法里的代码看下就会明白了
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater mInflater = LayoutInflater.from(context);
//每次调用 都实例化layout 效率非常低 ,而且每次在下面都创建了好几个View
convertView = mInflater.inflate(R.layout.user_list, null);
ImageView imgUserImg = (ImageView) convertView.findViewById(R.id.imgUserImg);
imgUserImg.setBackgroundResource((Integer) listData.get(position).get("imgUserImg"));
TextView tvUserName = (TextView) convertView.findViewById(R.id.tvUserName);
tvUserName.setText((String)listData.get(position).get("tvUserName"));
Log.d("getView", (String)listData.get(position).get("tvUserName"));
TextView tvUserMoney = (TextView) convertView.findViewById(R.id.tvUserMoney);
tvUserMoney.setText(String.valueOf(listData.get(position).get("tvUserMoney")));
CheckBox check = (CheckBox) convertView.findViewById(R.id.ckUser);
。。。。。。
ListView 针对每个item,要求 adapter “返回一个视图” (getView),也就是说ListView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到ListView的长度,然后根据这个长度,调用getView()一行一行的绘制ListView的每一项。如果你的getCount()返回值是0的话,列表一行都不会显示,如果返回1,就只显示一行。返回几则显示几行。如果我们有几千几万甚至更多的item要显示怎么办?为每个Item创建一个新的View?不可能!!!实际上Android早已经缓存了这些视图,大家可以看下下面这个截图来理解下,这个图是解释ListView工作原理的最经典的图了大家可以收藏下,不懂的时候拿来看看,加深理解,其实Android中有个叫做Recycler的构件,顺带列举下与Recycler相关的已经由Google做过N多优化过的东东比如:AbsListView.RecyclerListener、ViewDebug.RecyclerTraceType等等,要了解的朋友自己查下,不难理解,下图是ListView加载数据的工作原理:
Log.d(TAG,"getView " + position + " " + convertView)
第一次刚进来的时(没有去滚动)结果如上面的右图所示(这里有个地方需要注意:listView的
android:layout_width="fill_parent" android:layout_height="fill_parent" 设为fill_parent)
然后往下划 如下图
这时convertView不是空值了!item1离开屏幕到Recycler中去了,然后item11被创建,再滚动下:
此时的convertView非空了,在item11离开屏幕之后,它的视图(…7d0)作为convertView容纳item12了.
了解完原理后就可以开始我们的优化工作了 先上代码吧:(就拷上核心代码,这里需要定义一个静态内部类来保存convertView)
public class myAdapter extends BaseAdapter {
......
//定义一个静态内部类 用来临时保存item上每行的数据
static class ViewHolder{
TextView tvUserName;
TextView tvUserMoney;
CheckBox check;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
Log.i("myAdapter", "getView -- " + position + " -- " + convertView);
ViewHolder holder;
if(convertView==null){
convertView = mLayoutInflater.inflate(R.layout.user_list, null);
holder = new ViewHolder();
holder.tvUserName = (TextView)convertView.findViewById(R.id.tvUserName);
holder.tvUserMoney = (TextView)convertView.findViewById(R.id.tvUserMoney);
holder.check = (CheckBox)convertView.findViewById(R.id.ckUser);
convertView.setTag(holder);
}else{
holder = (ViewHolder)convertView.getTag();
}
//重新赋值
holder.tvUserName.setText((String)listData.get(position).get("tvUserName"));
holder.tvUserMoney.setText(String.valueOf(listData.get(position).get("tvUserMoney")));
flag = Boolean.parseBoolean((String)listData.get(position).get("ckUser"));
holder.check.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
flag = false;//如果有改变事件已改变事项为准
if (isChecked) {
state.put(position, isChecked);
listData.get(position).put("ckUser","true");
} else {
state.remove(position);
listData.get(position).put("ckUser","false");
}
}
});
holder.check.setChecked(flag?true:(state.get(position)==null?false:true));
return convertView;
}
......
}
里的
setTag 和 getTag方法 这里就不解释了可以去google下
简单说setTag就是保存一些数据 供getTag方法使用
我们这里先调用 setTag 保存 holder 然后调用getTag取出holder进行设值