android listView 重写Adapter方法getView的性能优化问题
2013-08-31 00:47
501 查看
1.为什么要重写Adapter 的getView方法
为什么要重写getView方法 可以看这里 androidlistView滚动时checkBox的状态不会保存的问题
2.在哪个地方会有性能问题
拿出 androidlistView滚动时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进行设值
相关文章推荐
- [Android]ListView的Adapter.getView()方法中延迟加载图片的优化
- [Android]ListView的Adapter.getView()方法中延迟加载图片的优化
- [Android]ListView的Adapter.getView()方法中延迟加载图片的优化
- Android自定义ListView或GridView适配器Adapter的getView方法不执行的问题
- 关于重写的listview adapter中,在getView()方法中,打印语句时,相同的position打印了多次,重复调用问题
- Android listview&gridview getview 方法多次调用问题解决方法
- 关于ListView的BaseAdapter中getView方法问题
- android listview继承BaseAdapter,自定义的适配器,getView方法执行多组循环解决方式
- Android-关于一个界面同级中需要两个listView时,一个ListView被嵌套在ScrollView中,ListView的适配器adapter中的getView执行次数重复问题
- 关于ListView中继承BaseAdapter重写getview的显示重复数据或报转换错误的问题
- 浅谈Android开发中ListView控件性能的一些优化方法
- NoScrollListView 设置 Adapter 后 getView() 方法 view 会进行复用的问题
- listview的重写方法getview的优化
- Android 重写lisview的adapter的getView方法,position一直是0
- Android 解决ListView、GridView在首次显示时adapter可能多次调用getView的问题
- ListView Adapter里的getView()方法重复调用问题
- Android listview&gridview getview 方法多次调用问题解决方法 并附上单页加载实现问卷调查适配器源代码
- [Android]ListView性能优化之视图缓存 解决listView显示重复问题
- Android ListView的适配器 Adapter 中GetView方法调用次数大于数据条数的问题
- android ListView 和Adapter 结合,但是不调用getView()方法??