android listview viewholder. when to use it, and when not to

∥☆過路亽.° 提交于 2019-12-18 07:46:11

问题


I have a ListView with a custom list adapter. In the getView() method, am using the ViewHolder 'pattern' as shown in the API Demos for ListView14.java. When i first render the list it seems to load correctly. However, the issue i'm running into is that when i scroll the list, i'm seeing the data for the list show up in the wrong rows (i.e. a TextView that should be in row 10 is showing up in row 2 for example). However, when I do not use the viewholder, and instead call findViewById() every time, then the list view renders correctly.


回答1:


However, the issue i'm running into is that when i scroll the list, i'm seeing the data for the list show up in the wrong rows (i.e. a TextView that should be in row 10 is showing up in row 2 for example).

Most likely, you are improperly recycling your rows, such that the ViewHolders you are manipulating are not the right ones for the row you are returning.

Here is a free excerpt from one of my books that goes into more about row recycling -- perhaps it will help you identify where things are going wrong.




回答2:


  • I faced same problem
  • Solved using below techninc
  • Reason : Adapter not Loaded Frequentlyy.
  • in Your Custom Adapter class add ViewHolder using Access Specifiers

    private static class ViewHolder {
    
            protected TextView itemName;
    
        }
    

In Get View method

    @Override

        public View getView(int position, View view, ViewGroup viewGroup) {

            // create a ViewHolder reference
            ViewHolder holder;

            //check to see if the reused view is null or not, if is not null then reuse it
            if (view == null) {
                holder = new ViewHolder();

                view = mLayoutInflater.inflate(R.layout.list_item, null);
                holder.itemName = (TextView) view.findViewById(R.id.list_item_text_view);

                // the setTag is used to store the data within this view
                view.setTag(holder);
            } else {
                // the getTag returns the viewHolder object set as a tag to the view
                holder = (ViewHolder)view.getTag();
            }
    // now Use Holder object toget Idss 

    holder.itemName.setText(" sample text based on position ");
    }

Important : And We should not set Any Tag for view object except Viewholder Object




回答3:


so i think i discovered the real issue here. when you set layout parameters on the fly for each row, you need to make sure you do it for all conditions. my problem was that if it was the first row, i set a layout param (like padding or margins etc), but then if it was a middle row, i didn't explicitly set those params thinking that it would just use what was inflated by the view inflater. This explains why it worked when i inflated the view each time. Here is a before & after:

BEFORE:

if (position == 0) {

            layoutParams.topMargin = uiHelper.getDip(15.0f);
            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,
                    RelativeLayout.TRUE);
            holder.actionMenu.setLayoutParams(layoutParams);

            holder.contentLayout.setBackgroundResource(R.drawable.top_row);

        } else if (position == posts.size() - 1) {
            holder.contentLayout
                    .setBackgroundResource(R.drawable.bottom_row);

            holder.contentLayout.setPadding(holder.contentLayout
                    .getPaddingLeft(),
                    holder.contentLayout.getPaddingTop(),
                    holder.contentLayout.getPaddingRight(),
                    holder.contentLayout.getPaddingBottom() +  uiHelper.getDip(10.0f));

        } else {
            holder.contentLayout
                    .setBackgroundResource(R.drawable.inner_row);
        }

AFTER:`

            layoutParams.topMargin = uiHelper.getDip(10.0f);
        holder.contentLayout.setPadding(holder.contentLayout
                .getPaddingLeft(),
                holder.contentLayout.getPaddingTop(),
                holder.contentLayout.getPaddingRight(),
                uiHelper.getDip(10.0f));
        if (position == 0) {

            layoutParams.topMargin = uiHelper.getDip(15.0f);
            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,
                    RelativeLayout.TRUE);

            holder.contentLayout.setBackgroundResource(R.drawable.top_row);

        } else if (position == posts.size() - 1) {
            holder.contentLayout
                    .setBackgroundResource(R.drawable.bottom_row);

            holder.contentLayout.setPadding(holder.contentLayout
                    .getPaddingLeft(),
                    holder.contentLayout.getPaddingTop(),
                    holder.contentLayout.getPaddingRight(),
                    uiHelper.getDip(20.0f));

        } else {

            holder.contentLayout
                    .setBackgroundResource(R.drawable.inner_row);

        }

        holder.actionMenu.setLayoutParams(layoutParams);


来源:https://stackoverflow.com/questions/3208897/android-listview-viewholder-when-to-use-it-and-when-not-to

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!