Recycling views in custom array adapter: how exactly is it handled?

后端 未结 5 878
栀梦
栀梦 2020-12-15 11:15

I am having an unclear issue concerning the recycling of views in a getView method of a custom array adapter.

I understand that elements are reused, but how do I kn

相关标签:
5条回答
  • 2020-12-15 11:51

    I understand that elements are reused, but how do I know exact what to implement in the first part of the if statement, and what in the second?

    The organization is quite simple once you get the hang of it:

    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;
    }
    

    For detailed explanations of how ListView's RecycleBin works and why ViewHolders are important watch Turbo Charge your UI, a Google I/O presentation by Android's lead ListView programmers.

    0 讨论(0)
  • 2020-12-15 11:56

    You want to create a ViewHolder class in your MainActivity. Something like

     static class ViewHolder
        {
            TextView tv1;
            TextView tv2;
        }
    

    then in your getView, the first time you get your Views from your xml in the if and reuse them after that in the 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();
            }
    
    0 讨论(0)
  • 2020-12-15 11:58

    The last part of the question I really couldn't grasp without a picture of the effect but for the first part "what to implement in the first part of the if statement, and what in the second" I think I've found the this implementation very common.

    You would find the view references first and store them to a static class ViewHolder which then you attach to the tag of the new inflated view. As the listview recycles the views and a convertView is passed getView you get the ViewHolder from the convertView's tag so you don't have to find the references again (which greatly improves performance) and update the view data with that of your object at the position given.

    Technically you don't care what position the view was since all you care for is the references to the views you need to update which are held within it's 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;
    }
    
    0 讨论(0)
  • 2020-12-15 12:00

    I would recommend that you use the View holder and convertview pattern to create your listView as it will be more efficient.Here is a good explanation of how it works with a re-use strategy. This will answer your question on how re-cycling works. If you want to refer to a code sample, I have it on GitHub.

    Hope this helps.

    0 讨论(0)
  • 2020-12-15 12:12

    It's easy. The first time no row is created, so you have to inflate them. Afterwards, the Android os may decide to recycle the views that you already inflated and that are not visible anymore. Those are already inflated and passed into the convertView parameter, so all you have to do is to arrange it to show the new current item, for example placing the right values into the various text fields.

    enter image description here

    In short, in the first part you should perform the inflation AND fill the values, in the second if (if convertView != null) you should only overwrite the field because, given the view has been recycled, the textviews contain the values of the old item.

    This post and this are good starting points

    0 讨论(0)
提交回复
热议问题