自定义数组适配器中的回收视图:它是如何处理的?

时间:2013-04-09 21:35:24

标签: android android-arrayadapter recycle

我对自定义数组适配器的getView方法中的视图回收有一个不明确的问题。

我理解元素是可以重用的,但是我怎么知道在if语句的第一部分中要实现什么,以及在第二部分中实现什么?

现在我有以下代码。由于删除了语句的第二部分中的代码,我得出了这个问题,这导致了前9个元素的列表,这些元素重复了多次而不是所有元素。我真的不知道究竟是什么造成了这个......

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

        if (row == null) {
            LayoutInflater inflater = ((Activity) context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);

            title = getItem(position).getTitle();
            size = calculateFileSize(position);

            txtTitle = (TextView) row.findViewById(R.id.txtTitle);
            tvFileSize = (TextView) row.findViewById(R.id.tvFileSize);

            txtTitle.setText(title);
            tvFileSize.setText(size);

        } else {

            title = getItem(position).getTitle();
            size = calculateFileSize(position);

            txtTitle = (TextView) row.findViewById(R.id.txtTitle);
            tvFileSize = (TextView) row.findViewById(R.id.tvFileSize);

            txtTitle.setText(title);
            tvFileSize.setText(size);
        }

        return row;
    } 

5 个答案:

答案 0 :(得分:15)

这很容易。第一次没有创建行,所以你必须给它们充气。之后,Android操作系统可能决定回收您已经膨胀并且不再可见的视图。这些已经被夸大并传递到convertView参数,所以你要做的就是安排它来显示新的当前项目,例如将正确的值放入各种文本字段。

enter image description here

简而言之,在第一部分中你应该执行膨胀并填充值,在第二部分if(if convertView != null)中你应该只覆盖该字段,因为,鉴于视图已被回收,textviews包含旧项目的价值。

This postthis是很好的起点

答案 1 :(得分:13)

  

我理解元素是可以重用的,但是我怎么知道在if语句的第一部分中要实现什么,以及在第二部分中实现什么?

一旦掌握了它,组织就会非常简单:

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

    if (convertView == null) {
        /* This is where you initialize new rows, by:
         *  - Inflating the layout,
         *  - Instantiating the ViewHolder,
         *  - And defining any characteristics that are consistent for every row */
    } else {
        /* Fetch data already in the row layout, 
         *    primarily you only use this to get a copy of the ViewHolder */
    }

    /* Set the data that changes in each row, like `title` and `size`
     *    This is where you give rows there unique values. */

    return convertView;
}

有关ListView的RecycleBin如何工作的详细解释以及为什么ViewHolders很重要,请观看Turbo Charge your UI,这是Android的主要ListView程序员的Google I / O演示。

答案 2 :(得分:5)

您想在ViewHolder中创建MainActivity课程。像

这样的东西
 static class ViewHolder
    {
        TextView tv1;
        TextView tv2;
    }

然后在getView中,第一次从Views中的xml获取if,然后在else

中重复使用它们
View rowView = convertView;
        if (rowView == null)
        {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            rowView = inflater.inflate(R.layout.layout_name_to_inflate, parent, false);
            holder = new ViewHolder();
            holder.tv1= (TextView) rowView.findViewById(R.id.textView1);
            holder.tv2 = (RadioGroup) rowView.findViewById(R.id.textView2);             
            rowView.setTag(holder);
        }
        else
        {
            holder = (ViewHolder) rowView.getTag();
        }

答案 3 :(得分:4)

我建议您使用View holder和convertview模式来创建listView,因为它会更有效。Here可以很好地解释它如何与重用策略一起使用。这将回答您关于再循环如何工作的问题。如果您想参考代码示例,我可以在GitHub上找到它。

希望这有帮助。

答案 4 :(得分:1)

问题的最后一部分,如果没有效果的图片我真的无法掌握,但第一部分“在if语句的第一部分实现什么,第二部分是什么”我认为我已经发现这个实现很常见。

您首先会找到视图引用并将它们存储到静态类ViewHolder,然后将其附加到新的膨胀视图的标记。由于listview会回收视图并传递convertView getView,因此您可以从convertView的标记中获取ViewHolder,这样您就不必再次找到引用(这极大地提高了性能)并使用给定位置的对象更新视图数据。

从技术上讲,您并不关心视图的位置,因为您所关心的只是对您需要更新的视图的引用,这些视图保存在ViewHolder中。

@Override
public View getView(int position, View convertView, ViewGroup container) {
    ViewHolder holder;
    Store store = getItem(position);
    if (convertView == null) {
        convertView = mLayoutInflater.inflate(R.layout.item_store, null);

        // create a holder to store references
        holder = new ViewHolder();

        // find references and store in holder
        ViewGroup logoPhoneLayout = (ViewGroup) convertView
                .findViewById(R.id.logophonelayout);
        ViewGroup addressLayout = (ViewGroup) convertView
                .findViewById(R.id.addresslayout);

        holder.image = (ImageView) logoPhoneLayout
                .findViewById(R.id.image1);
        holder.phone = (TextView) logoPhoneLayout
                .findViewById(R.id.textview1);
        holder.address = (TextView) addressLayout
                .findViewById(R.id.textview1);

        // store holder in views tag
        convertView.setTag(holder);
    } else {

        // Retrieve holder from view
        holder = (ViewHolder) convertView.getTag();
    }

    // fill in view with our store (at this position)
    holder.phone.setText(store.phone);
    holder.address.setText(store.getFullAddress());

    UrlImageViewHelper.setUrlDrawable(holder.image, store.storeLogoURL,
            R.drawable.no_image);

    return convertView;
}

private static class ViewHolder {
    ImageView image;
    TextView phone;
    TextView address;
}