ListView的优化

来源:互联网 发布:淘宝刷客论坛 编辑:程序博客网 时间:2024/06/16 23:43

前面在说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的优化的分享就到这。欢迎大家在评论区指出错误与不足之处。

谢谢观看

0 0