listview的复用机制

2015/6/9 posted in  Android

本文介绍了listview的复用机制

listview 的item只会创建一定数量,只会创建的view会复用之前的

测试代码如下

自定义一个adapter

/**
 * Created by xuyushi on 15/8/9.
 */
public class MyAdapter extends ArrayAdapter<String > {

    private static final String TAG = "MyAdapter";
    private int resourceId ;

    public MyAdapter(Context context, int textViewResourceId, List<String> objects) {
        super(context, textViewResourceId, objects);
        this.resourceId = textViewResourceId;
    }


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

        ViewHolder myViews;
        String string =  getItem(position);
        if (convertView == null) {
            Log.d(TAG, "为空:" + position);
            myViews = new ViewHolder();
            convertView = LayoutInflater.from(getContext()).inflate(resourceId, null);
            myViews.mNameText = (TextView) convertView.findViewById(R.id.list_item);
            convertView.setTag(myViews);
        } else {
            myViews = (ViewHolder) convertView.getTag();
            Log.d(TAG, "不为空:" + position);
        }

        myViews.mNameText.setText(string);
        return convertView;
    }

    static class ViewHolder {
        private TextView mNameText;
    }
}

可以看到 随着listview 往下滚动,打印的都为”不为空"

那么问题来了

比如异步加载图片,最终造成界面显示的混乱

举个例子:listview中有一个imageview,动态的加载网络图片

@Override  
    public View getView(int position, View convertView, ViewGroup parent)  
    {  
        final String url = getItem(position);  
        View view;  
        if (convertView == null)  
        {  
            view = LayoutInflater.from(getContext()).inflate(R.layout.photo_layout, null);  
        } else  
        {  
            view = convertView;  
        }  
        final ImageView photo = (ImageView) view.findViewById(R.id.photo);  
        // 给ImageView设置一个Tag,保证异步加载图片时不会乱序  
        photo.setTag(url);  
        new LoadImgTask(photo).execute(url);  
        return view;  
    } 

当第一页的imageview开启异步线程加载图片时候,listview下翻,新的item会复用之前恩item,而且setTag会覆盖之前的tag。当第一屏的ItemView的图片下载完成后,如果直接findViewByTag然后设置图片会显示在第二屏上,就混乱了,所以一般在显示前都会判断photo.getTag().equals(url);确定了再显示。也就是说第一屏的ItemView图片下载完了,但是Tag被覆盖了,所以即使下载完成了,也不会有任何显示。这就解释了为什么我们防止混乱的代码需要那样去写。