转载请注明出处

最近碰到的面试题中经常会碰到问"ListView的优化"问题。所以就拿自己之前写的微博客户端的程序做下优化。
自己查了些资料,看了别人写的博客,得出结论,ListView优化大致从以下几个角度:
1.复用已经生成的convertView;
2.添加viewHolder类;
3.缓存数据(图片缓存);
4.分页加载。

一、复用convertView
首先讲下ListView的原理:ListView中的每一个Item显示都需要Adapter调用一次getView的方法,这个方法会传入一个convertView的参数,返回的View就是这个Item显示的View。如果当Item的数量足够大,再为每一个Item都创建一个View对象,必将占用很多内存,创建View对象(mInflater.inflate(R.layout.lv_item, null);从xml中生成View,这是属于IO操作)也是耗时操作,所以必将影响性能。Android提供了一个叫做Recycler(反复循环器)的构件,就是当ListView的Item从上方滚出屏幕视角之外,对应Item的View会被缓存到Recycler中,相应的会从下方生成一个Item,而此时调用的getView中的convertView参数就是滚出屏幕的Item的View,所以说如果能重用这个convertView,就会大大改善性能。

图解:一个屏幕最多显示7个Item,如果当Item1滑出屏幕,此时Item1 的View被添加进Recycler中,相应的在下部要产生一个Item8,这时调用getView方法,convertView参数就是Item1 的View。

(1)Item固定高度
测试Demo:

 public View getView(int position, View convertView, ViewGroup parent) {
     System.out.println("getView " + position + " " + convertView);
     ViewHolder holder = null;
     if (convertView == null) {
         convertView = mInflater.inflate(R.layout.lv_item, null);
         holder = new ViewHolder();
         holder.textView = (TextView)convertView.findViewById(R.id.tv_text);
         convertView.setTag(holder);
     } else {
         holder = (ViewHolder)convertView.getTag();
     }
     holder.textView.setText(mData.get(position));
     return convertView;
 }

首先程序启动,9个Item显示调用getView方法,这时的convertView都是null,因为没有任何Item被滑出屏幕缓存到Recycler中。所以打印的Log如图:

继续向上滑动屏幕,当Item1,Item2,Item3.....陆续滑出屏幕之后,他们之前的View得到重用。所以最终屏幕上就只是这10个View反复循环重用了(因为屏幕最多显示10个Item)。

然后我尝试把屏幕往回滚,重新滚到前面。

图解:屏幕从显示Item 17-Item26 滚到显示Item13-Item22。分析这个过程,当滚动一个Item时,Item26消失,Item16出现,所以Item16又将复用Item26的View,观察Log,的确如此,其他依次类推。仔细分析,有这样一个规律:无论怎么重用convertView,一个position的Item永远使用一个view。(比如此例中Item13 永远显示的是 5272fb00的View)。

(2)Item高度不固定
以上的例子是针对于每个Item的高度是固定的,所以很容易从定量中计算出每一个屏幕能够显示的最多Item数量。如果当一个Item的高度很根据不同情况的数据发生变化时,这样就无法得知最多显示的Item数量。
看一个例子,我的微博客户端程序,都知道微博有的有转载,有的有图片,所以说微博的每一个Item高度是不固定的。同样在getView中打出日志,显示如下图:

图解:因为没有固定的Item高度,无法计算一个屏幕中能够显示的最大高度,系统会会先创建一个View,第一轮是用这个View来试探能放多少个item,试探出结果可以放3个Item,所以第二轮的0-2才是真正创建的View,屏幕上显示了3个Item。当往下滚时,Item0没有完全出去,下面有来了个Item3,所以这时的Item有创建了一个View,屏幕上此时显示4个Item。之后4个Item就是做多显示的数量,再往上滚动,convertView就开始重用了,Item4和Item0的View是一个对象。

二、使用viewHolder类

我们都知道在getView方法中的操作是这样的:先从xml中创建view对象(inflate操作,我们采用了重用convertView方法优化),然后在这个view去findViewById,找到每一个子View,如:一个TextView等。这里的findViewById操作是一个树查找过程,也是一个耗时的操作,所以这里也需要优化,就是使用viewHolder,把每一个子View都放在Holder中,当第一次创建convertView对象时,把这些子view找出来。然后用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。当第二次重用convertView时,只需从convertView中getTag取出来就可以。

测试Demo:

 public View getView(int position, View convertView, ViewGroup parent) {
         System.out.println("getView " + position + " " + convertView);
         ViewHolder holder = null;
         if (convertView == null) {
             convertView = mInflater.inflate(R.layout.lv_item, null);
             holder = new ViewHolder();
             holder.textView = (TextView)convertView.findViewById(R.id.tv_text);
             convertView.setTag(holder);
         } else {
             holder = (ViewHolder)convertView.getTag();
         }
         holder.textView.setText(mData.get(position));
         return convertView;
     }
}

 public static class ViewHolder {
     public TextView textView;
 }

ListView的性能优化之convertView和viewHolder的更多相关文章

  1. 转-ListView的性能优化之convertView和viewHolder

    ListView的性能优化之convertView和viewHolder 2014-05-14 参考:http://www.cnblogs.com/xiaowenji/archive/2010/12/ ...

  2. Android之ListView性能优化——使用ConvertView和ViewHolder

    使用ConvertView和ViewHolder的优化是针对ListView的Adapter(BaseAdapter)的.这种优化的优点如下: 1)重用了ConveertView,在很大程度上减少了内 ...

  3. 【Android】以BaseAdapter做适配器的ListView及其性能优化

    适配器的Java类 package com.app.adapter; import org.json.JSONArray; import org.json.JSONObject; import and ...

  4. 安卓ListView的性能优化

    在安卓APP中LIstView这个控件可以说基本上是个APP就会用到,但是关于ListView除了需要了解其最基本的用法外,作为一个要做出高性能APP的程序员还需了解一些关于LIstView控件性能优 ...

  5. ListView的性能优化

    @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHol ...

  6. ListView之性能优化

    listview加载的核心是其adapter,本文通过减少adapter中创建.处理view的次数来提高listview加载的性能,总共分四个层次: 0.最原始的加载 1.利用convertView ...

  7. 安卓中listview中性能优化的处理

    1.在adapter中的getView方法中尽量少使用逻辑 不要在你的getView()中写过多的逻辑代码,我们能够将这些代码放在别的地方.比如: 优化前的getView(): @Override p ...

  8. ListView性能优化——convertView&viewHolder

    ListView优化大致从以下几个角度:1.复用已经生成的convertView:2.添加viewHolder类:3.缓存数据(图片缓存):4.分页加载. 具体方案: 1.如果自定义适配器,那么在ge ...

  9. Android之ListView性能优化——一行代码绑定数据——万能适配器

    如下图,加入现在有一个这样的需求图,你会怎么做?作为一个初学者,之前我都是直接用SimpleAdapter结合一个Item的布局来实现的,感觉这样实现起来很方便(基本上一行代码就可以实现),而且也没有 ...

随机推荐

  1. 解决UICollectionView ReloadData闪一下(隐式动画)

    方式一: [UIView setAnimationsEnabled:NO]; [collectionView performBatchUpdates:^{ [collectionView reload ...

  2. 利用maven的resources、filter和profile实现不同环境使用不同配置文件

    基本概念说明(resources.filter和profile): 1.profiles定义了各个环境的变量id 2.filters中定义了变量配置文件的地址,其中地址中的环境变量就是上面profil ...

  3. ACM YTU 1012 u Calculate e

    u Calculate e Problem Description A simple mathematical formula for e is where n is allowed to go to ...

  4. Spring MVC 3.2 406 Not Acceptable

    Spring MVC 3.2 406 Not Acceptable 这个报错主要是因为SpringMVC配置文件配置问题. 修改步骤如下: 首先,修改spring-mvc.xsd为 spring-mv ...

  5. IE6 for WIN8

    分享一款微软原生内核的Ie6,绿色免安装,无广告,无插件. 点击下载IE6 for WIN8 来源:子涵的博客

  6. Jquery常用功能

    jQuery 1.4给开发者带来了很多值得兴奋的新特性,同时使用jQuery的人也越来越多,为了方便大家对jQuery的使用,下面列出了一些jQuery使用技巧.比如有禁止右键点击.隐藏搜索文本框文字 ...

  7. centos下的lnmp环境搭建

    1.配置centos的第三方yum源,因为原始的yum是无法安装nginx的 wget http://www.atomicorp.com/installers/atomic  下载atomic yum ...

  8. WPF扩展标记

    标记扩展和 WPF XAML,标记扩展是 XAML 语言以及 XAML 服务的 .NET 实现的常规功能 XAML 处理器和标记扩展 XAML 分析器可将特性值解释为可转换成基元的文本字符串,或可通过 ...

  9. 【算法】一般冒泡排序 O(n^2) 稳定的 C语言

    冒泡排序 一.算法描述 假设序列中有N个元素: 第一趟选取第一个元素作为关键字,从左至右比较,若遇到比它小的则放到它左边(也即两数进行交换),若遇到比它大的,则改为选取该元素作为关键字完成后续的比较, ...

  10. 虚拟机下linux上网

    一.概述 1. 常见的上网方式 有以下两种: 桥接 NAT(推荐) 有关虚拟机几种不同联网方式的讲述,可以参考VMware网络选项分析 通常的配置步骤: <1> 配置PC端 <2&g ...