ListView性能优化

概述

在Android开发过程中ListView是一个很常用的组件,但当使用ListView加载大量数据时,可能会出现卡顿的现象,那么我们该如何优化ListView使之变得流畅易用呢?

ListView优化主要有下面几个方面:

  1. convertView重用(减少创建View的消耗)
  2. ViewHolder的子View复用(减少创建 findViewById() 的消耗)
  3. 分页加载
  4. 缓存数据复用

ConvertView重用

首先讲下ListView的原理:

ListView中的每一个Item显示都需要Adapter调用一次 getView() 的方法,这个方法会传入一个 convertView 的参数,这个方法返回的View就是这个Item显示的View。

如果当Item的数量足够大,再为每一个Item都创建一个View对象,必将占用很多内存空间,即创建View对象(如以下代码,从xml中生成View,这是属于IO操作)是耗时操作,所以必将影响性能。

mInflater.inflate(R.layout.lv_item, null);

Android提供了一个叫做 Recycler (反复循环)的构件,就是当ListView的Item从滚出屏幕视角之外,对应Item的View会被缓存到Recycler中,相应的会从生成一个Item,而此时调用的getView中的convertView参数就是滚出屏幕的缓存Item的View,所以说如果能重用这个convertView,就会大大改善性能。

Recycler的原理

这里写图片描述

  1. 如果你有10亿个项目(item),其中只有可见的项目存在内存中,其他的在Recycler中。

  2. ListView先请求一个type1视图(getView)然后请求其他可见的项目。convertView在getView中是空(null)的。

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

那么,我们怎么重用它呢?贴代码

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

        /**
         * (!!!优化的部分)
         *  如果 convertView 是 空(null) 的话 ,就创建新的 convertView , 否则直接使用convertView
         */
        if(convertView == null){
            convertView = LayoutInflater.from(context).inflate(R.layout.adapter_item, null,true);
        }

        /**
         *  初始化 convertView 中的组件(可进一步优化)
         */
        TextView mLeftTv = (TextView) convertView.findViewById(R.id.id_tv_left);
        TextView mRightTv = (TextView) convertView.findViewById(R.id.id_tv_right);

        /**
         *  赋值
         */
        DataBean bean = mList.get(position);

        mLeftTv.setText(bean.getName());
        mRightTv.setText(bean.getSchool());

        return convertView;
    }

当 convertView 不存在时,即第一次使用它,我们就创建一个item布局的View对象并赋给convertView,以后使用convertView时,只需 复用之前创建的convertView,不需要再次创建item的布局对象了,这样便提高了性能。

ViewHolder的子View复用

我们都知道在getView()方法中的操作是这样的:

先从xml中创建view对象(inflate操作,我们采用了重用convertView方法优化),然后在这个view去findViewById,找到每一个item的子View的控件对象,如:ImageView、TextView等。

这里的 findViewById 操作是一个树查找过程,也是一个耗时的操作,所以这里也需要优化,就是 使用ViewHolder,把每一个item的子View控件对象都放在Holder中 ,当第一次创建convertView对象时,便把这些item的子View控件对象findViewById实例化出来并保存到ViewHolder对象中。

然后用convertView的setTag将viewHolder对象设置到Tag中, 当以后加载ListView的item时便可以直接从Tag中取出复用ViewHolder对象中的,不需要再findViewById找item的子控件对象了。这样便大大提高了性能。

话不多说,上代码

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

        ViewHolder mViewHolder = null;
        /**
         *  如果 convertView 是 空(null) 的话 ,就创建新的 convertView , 否则直接使用convertView
         */
        if(convertView == null){
            convertView = LayoutInflater.from(context).inflate(R.layout.adapter_item, null,true);
            /**
             * 初始化 mViewHolder
             */
            mViewHolder = new ViewHolder();
            mViewHolder.mLeftTv = (TextView) convertView.findViewById(R.id.id_tv_left);
            mViewHolder.mRightTv = (TextView) convertView.findViewById(R.id.id_tv_right);
            /**
             *  将设置好后的 mViewHolder 放入convertView 的 Tag 中。
             */
            convertView.setTag(mViewHolder);
        }else{
            /**
             *  从 convertView 的 Tag 中取出 mViewHolder。
             */
            mViewHolder = (ViewHolder) convertView.getTag();
        }

        DataBean bean = mList.get(position);
        /**
         * (!!!优化的地方)
         *  复用 convertView 的 子View控件对象
         */
        mViewHolder.mLeftTv.setText(bean.getName());
        mViewHolder.mRightTv.setText(bean.getSchool());

        return convertView;
    }

    /**
     *  新建的 ViewHolder 内部类
     */
    private final class ViewHolder{
        TextView mLeftTv;
        TextView mRightTv;
    }

分页加载

一个应用在用 ListView 展现大量数据时,不会将全部的可用数据都呈现给用户,因为这不管对于服务端还是客户端来说都是不小的压力,因此,很多应用都是采用分批次加载的形式来获取用户所需的数据。

传送门:http://blog.csdn.net/liuhe688/article/details/6852523

缓存数据复用

若 ListView 中要展示的数据需要联网取得,则在首次联网获取数据的时候将数据缓存到本地,然后在为 ListView 设置数据源前加个判断,优先使用本地数据即可。

缓存一些普通字符串数据等可自己来实现,缓存图片则可直接使用 Universal-Image-Loader 等框架来实现,节约效率。

参考文章:
http://blog.csdn.net/u010687392/article/details/45620541
http://www.cnblogs.com/xiaowenji/articles/1900579.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值