您的位置:首页 > 移动开发 > Android开发

android listView 重写Adapter方法getView的性能优化问题

2013-08-31 00:47 501 查看

1.为什么要重写Adapter 的getView方法

为什么要重写getView方法 可以看这里 android
listView滚动时checkBox的状态不会保存的问题

2.在哪个地方会有性能问题

拿出 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);
。。。。。。


以上代码你会发现:每次加载item的时候,都要加载一下布局文件,然后生成一个新的convertView View对象,然后通过View找到对应的ImageView和TextView,正如我们所知道的那样,加载布局文件时很耗时的,特别是在操作比较频繁 情况下,这是不可忍受的,所以会导致ANR现象。

3.listView工作原理


ListView的工作原理如下:

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加载数据的工作原理:




下面简单说下上图的原理:

如果你有几千几万甚至更多的选项(item)时,其中只有可见的项目存在内存(内存内存哦,说的优化就是说在内存中的优化!!!)中,其他的在Recycler中

ListView先请求一个type1视图(getView)然后请求其他可见的项目。convertView([b]convertView是getView的第2个参数)在getView中是空(null)的[/b]

当item1滚出屏幕,并且一个新的项目从屏幕低端上来时,ListView再请求一个type1视图。convertView此时不是空值了,它的值是item1。你只需设定新的数据然后返回convertView,不必重新创建一个视图

来看下实现测试的结果吧:我们在getView方法里打印出convertView的值

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了.

4.优化代码

了解完原理后就可以开始我们的优化工作了 先上代码吧:(就拷上核心代码,这里需要定义一个静态内部类来保存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进行设值
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐