Android——ListView学习笔记(二)关于提升ListView的运行效率

提升ListView的运行效率笔记

我做的 ListView 的时每个子项会显示一张图和一行文字,效果如下图:

因为要显示一张图和一段文字,直接使用 ArrayAdapter 适配器无法做到,就需要创建一个自定义适配器继承 ArrayAdapter 并重写 getView() 方法,先贴出没有进行提升效率前的自定义适配器类的代码:

public class AnimalAdapter extends ArrayAdapter<Animal> {

    private int resouceId;

    public AnimalAdapter (Context context, int textViewResouceId, List<Animal> object){
        super(context,textViewResouceId,object);
        resouceId = textViewResouceId;
    }

    @Override
    public View getView(int position, View converView, ViewGroup parent){
        Animal animal = getItem(position);  //获取当前子项的Animal实例
        View view = LayoutInflater.from(getContext()).inflate(resouceId,parent,false);
        ImageView animalImage = (ImageView)view.findViewById(R.id.animal_image);
        TextView animalName = (TextView)view.findViewById(R.id.animal_name);
        animalImage.setImageResource(animal.getImageId());
        animalName.setText(animal.getName());
        return view;
    }
}

Animal 类就是每个子项里要显示的数据类,包括一个 int 类型的图片 Id,和一个 String 类型的动物名字。

在上面那段代码中,每次 ListView 界面滚动时,都会为新进入屏幕的子项重新加载布局,没有将滚出屏幕的子项的 View 进行复用(就是 getView() 方法中的 converView 参数),并且每次都会创建新的 ImageView 和 TextView 对象来获取控件实例,这样运行效率会很低,下面分两部来进行优化:

第一步,修改 getView() 方法,复用 converView:

public View getView(int position, View converView, ViewGroup parent){
    Animal animal = getItem(position);  //获取当前子项的Animal实例
    View view;
    if (converView == null){
            view = LayoutInflater.from(getContext()).inflate(resouceId,parent,false);
    }else {
            view = converView;
    }
    ImageView animalImage = (ImageView)view.findViewById(R.id.animal_image);
    TextView animalName = (TextView)view.findViewById(R.id.animal_name);
    animalImage.setImageResource(animal.getImageId());
    animalName.setText(animal.getName());
    return view;
}

可以看到,在中间加了一个if判断,判断 converView 是否为空,不为空就还是用 LayoutInflater 为子项加载我们传入的布局,因为在刚进入 ListView 界面时是没有 converView 的,需要先为整个屏幕创建足够的子项 View,当滑动时有子项滚出屏幕了才有 converView,所以当有子项滚出屏幕 converView 不为空时才能对其进行复用。

第二部,在第一步的基础上添加一个内部类 ViewHolder,用于对控件的实例进行缓存:

class ViewHolder{
    ImageView animalImage;
    TextView animalName;
}

在 getView 中,当 converView 为空时实例化一个新的 ViewHolder 对象,将控件的实例都存放在 ViewHolder 中,然后调用 view 的 setTag() 方法将 ViewHolder 对象储存在 view 中,那样,当重用 converView 时就可以用 getTag() 方法将 ViewHolder 重新取出来直接设置新的要显示的 Animal 实例信息就可以了,不需要再重新绑定获取控件实例了。

public View getView(int position, View converView, ViewGroup parent){
    Animal animal = getItem(position);  //获取当前子项的Animal实例     
    View view;
    ViewHolder viewHolder;
    //当converView不为空时,则对converView进行回收重用,提高运行效率
    if (converView == null){
        view = LayoutInflater.from(getContext()).inflate(resouceId,parent,false);
        viewHolder = new ViewHolder();
        viewHolder.animalImage = (ImageView)view.findViewById(R.id.animal_image);
        viewHolder.animalName = (TextView) view.findViewById(R.id.animal_name);
        view.setTag(viewHolder);
    }else {
        view = converView;
        viewHolder = (ViewHolder) view.getTag();
    }
    viewHolder.animalImage.setImageResource(animal.getImageId());
    viewHolder.animalName.setText(animal.getName());
    return view;
}        

经过上面两部是优化后,就可以提升 ListView 的运行效率了。

代码和优化方法都是参考《第一行代码:Android》,这里仅作学习笔记加深理解。

猜你喜欢

转载自www.cnblogs.com/mulin1999/p/13171219.html