ListView的优化

前面在说ListView的时候我们说,这是android中一个使用非常广泛的控件,所以呢这里特别想强调一下这个控件的优化问题。

我们说我们在getView()方法中都会执行两个耗时操作:inflate方法获取布局对象,findViewById方法获取控件对象,所以限制这两种方法的使用就能有效提高ListView 的性能。

对于每个新的item的出现就要调用一次getView的方法,所以在实际的操作中,每一次出现手势滑动,就要调用getView的方法。所以我们的解决办法是:对于inflate方法我们使用convertView解决,称为一级优化,findViewById使用ViewHolder解决,称为二级优化,二级优化必须在一级优化的基础上。

使用convertView优化

还是采用前面的代码:

package com.example.dreamcreationman.listview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;
import java.util.Map;

/**
 * Created by Dream on 2017/2/21.
 */

public class MyAdapter extends BaseAdapter {

    List<Map<String,Object>> list;
    LayoutInflater inflater;

    public MyAdapter(Context context) {
        this.inflater=LayoutInflater.from(context);
    }

    public void setList(List<Map<String, Object>> list) {
        this.list = list;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int position) {
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
       //未优化代码 View view= inflater.inflate(R.layout.ti,null);

        if(convertView==null){
            convertView=inflater.inflate(R.layout.ti,null);
        }
      ImageView logo= (ImageView) convertView.findViewById(R.id.logo);
      TextView  name = (TextView) convertView.findViewById(R.id.name);
     TextView  version = (TextView) convertView.findViewById(R.id.version);
      TextView  size = (TextView) convertView.findViewById(R.id.size);

        Map map=list.get(position);
        logo.setImageResource((Integer) map.get("logo"));
        name.setText((String) map.get("name"));
        version.setText((String) map.get("version"));
        size.setText((String) map.get("size"));
        //修改返回值
        return convertView;
    }
}

为什么用了convertView就能够达到优化的效果呢?

android里有一个循环回收器的Recycler,用于回收不显示在屏幕上的View。

第一屏的View渲染当然就不可避免了,但是当遇到手势操作下滑的时候,第一屏原来上方的item就被滑出了屏幕,此时,第一个item就会被回收到Recycler的回收池里,同时新的item也在进行产生,截至到目前,convertView还没发挥作用。然后再往上滑,此时,原来第一个item的回收已经完成,那么该再产生的item就直接使用第一个item的缓存数据,以此类推。也就是说,其实在整个过程中,总共参与了调用反射机制就是第一屏的View加一次,然后就是在循环利用视图缓存。而且这个更好的是再次上滑的时候也是如此。所以这个Recycler回收缓冲池大大减少了inflater的调用(当然·有的item只能显示半个的时候。算作一个,因为此时android也是完全渲染的)。

使用ViewHolder优化

package com.example.dreamcreationman.listview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;
import java.util.Map;

/**
 * Created by Dream on 2017/2/21.
 */

public class MyAdapter extends BaseAdapter {

    List<Map<String,Object>> list;
    LayoutInflater inflater;

    public MyAdapter(Context context) {
        this.inflater=LayoutInflater.from(context);
    }

    public void setList(List<Map<String, Object>> list) {
        this.list = list;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int position) {
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //View view= inflater.inflate(R.layout.ti,null);

        ViewHolder holder=null;
        if(convertView==null){
            convertView=inflater.inflate(R.layout.ti,null);

            holder=new ViewHolder();
            holder.logo= (ImageView) convertView.findViewById(R.id.logo);
            holder.name = (TextView) convertView.findViewById(R.id.name);
            holder.version = (TextView) convertView.findViewById(R.id.version);
            holder.size = (TextView) convertView.findViewById(R.id.size);
            convertView.setTag(holder);
        }else{
            holder= (ViewHolder) convertView.getTag();
        }


        Map map=list.get(position);
        holder.logo.setImageResource((Integer) map.get("logo"));
        holder.name.setText((String) map.get("name"));
        holder.version.setText((String) map.get("version"));
        holder.size.setText((String) map.get("size"));

        return convertView;
    }
    public static class ViewHolder{
        ImageView logo;
        TextView  name;
        TextView  version;
        TextView  size;
    }
}

getTag();存储的是Object对象,所以要强转下类型。

为什么ViewHolder能够进行优化呢?

ViewHolder是一个内部类,这里面存放了我们需要加载的控件对象。同样的第一屏的View渲染不可避免,同时将ViewHolder直接放给convertView,遇到手势操作下滑,第一屏原来上方的item被滑出,下一次直接调用else的方法。然后再往上滑,此时,原来第一个ViewHolder的回收已经完成,当再次使用到convertView时,直接利用ViewHolder来进行。以此类推,就大大减少了findViewById的调用。

但是由于每行的内容都不同,需要每次加载更新,所以下面的内容不能写在if语句里执行。

Map map=list.get(position);
        holder.logo.setImageResource((Integer) map.get("logo"));
        holder.name.setText((String) map.get("name"));
        holder.version.setText((String) map.get("version"));
        holder.size.setText((String) map.get("size"));

好了,关于ListView的优化的分享就到这。欢迎大家在评论区指出错误与不足之处。

谢谢观看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值