views:

32

answers:

3

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.

A: 

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.

CommonsWare
A: 

@CommonsWare (couldnt post this in a comment, so i'm posting it here)

i do have some logic in the getView() method that sets some click event handlers on some ui elements, changes the padding if the row is the top or bottom row, and loops over some child objects appending the text to a stringbuilder that then gets HTML'ized and put in the text of the view. like this:

        int numComments = msg.getComments().size();
        StringBuilder b = new StringBuilder();
        if (numComments > 0) {
            for (int i = 0; i < numComments; i++) {
                PulseActivity comment = msg.getComments().get(i);
                String htmlText = MessageFormat.format(
                        pulseCommentTemplate,
                        comment.getAuthor().getName(), comment.getText(),
                        comment.getRelativeTime());


                b.append(htmlText);

                if (i < numComments - 1) {

                    b.append("<br>");
                }
            }
            holder.commentText.setVisibility(View.VISIBLE);
            holder.commentText.setText(Html.fromHtml(b.toString()));
        } else {
            holder.commentText.setVisibility(View.GONE);
        }`

the holder.commentText is the text view that seems to get rendered in the wrong view... other than that it basically looks the same as in your book as well as in the API Demos...

Ben
you can always edit your question instead of posting additional details as an answer.
Janusz
thanks, yeah this was more of a reply to commonsware, but it was too big for the comment block...
Ben
+1  A: 

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);
Ben