How to stop ListView recycling?

1.1k views Asked by At

I'm an Android beginner and I can't figure out why this is happening.

Activity Screenshot:

enter image description here

Everything works fine except when I scroll down (hence why I think it has to do with recycling)... So when I scroll back up and attempt to undo the vote (red arrow) on the first post, it thinks the post is voted down!

Alternatively, it may also think the down-vote ImageButton drawable is empty - see code). If I don't scroll, it works perfectly.

getView code:

public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        holder = new ViewHolder();
        // inflate the list item
        convertView = this.inflater.inflate(R.layout.row_layout, parent, false);            
        // get views 
        holder.profilePic = (ImageView) convertView.findViewById(R.id.profilePic);
        holder.username = (TextView) convertView.findViewById(R.id.username);
        holder.day = (TextView) convertView.findViewById(R.id.day);
        holder.rating = (TextView) convertView.findViewById(R.id.rating);
        holder.textPost = (TextView) convertView.findViewById(R.id.textPost);
        holder.ratingUp = (ImageButton) convertView.findViewById(R.id.ratingUp);
        holder.ratingDown = (ImageButton) convertView.findViewById(R.id.ratingDown);
        convertView.setTag(holder);

    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    final Drawable up_clicked = context.getResources().getDrawable(R.drawable.ic_action_rate_up_clicked);
    final Drawable up_unClicked = context.getResources().getDrawable(R.drawable.ic_action_rate_up);
    final Drawable down_clicked = context.getResources().getDrawable(R.drawable.ic_action_rate_down_clicked);
    final Drawable down_unClicked = context.getResources().getDrawable(R.drawable.ic_action_rate_down);

    Post post = cityFeed.get(position);
    holder.profilePic.setImageResource(post.getDrawableID());
    holder.username.setText(post.getUsername());
    holder.day.setText(post.getDay());
    holder.rating.setText(post.getRating());
    holder.textPost.setText(post.getText());        

    db = new DatabaseHandler(context);
    String userVotesUp = null;
    userVotesUp = db.getUserVotes("up");
    if (userVotesUp == null) {
        userVotesUp = "";
    }
    String userVotesDown = null;
    userVotesDown = db.getUserVotes("down");
    if (userVotesDown == null) {
        userVotesDown = "";
    }
    String postID = post.getPostID();
    if (userVotesUp.contains(postID)) {
        holder.ratingUp.setImageDrawable(up_clicked);
    } else if (userVotesDown.contains(postID) && userVotesUp != null) {
        holder.ratingDown.setImageDrawable(down_clicked);
    } else {
        holder.ratingUp.setImageDrawable(up_unClicked);
        holder.ratingDown.setImageDrawable(down_unClicked);
    }
    db.close();

    holder.ratingUp.setTag(position);
    holder.ratingDown.setTag(position);

    holder.ratingUp.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View convertView) {

            // get post details using button tag
            int pos = (Integer)convertView.getTag();
            Post post = cityFeed.get(pos);
            String postID = post.getPostID();
            String ratingString = post.getRating();
            int ratingValue = Integer.parseInt(ratingString);               
            RelativeLayout parent = (RelativeLayout)convertView.getParent().getParent();
            TextView ratingView = (TextView)parent.findViewById(R.id.rating);
            ImageButton up = (ImageButton)parent.findViewById(R.id.ratingUp);
            ImageButton down = (ImageButton)parent.findViewById(R.id.ratingDown);

            // if the post is not voted down...
            if (down.getDrawable() == down_unClicked) {             
                // if the post is not voted up...
                if (up.getDrawable() == up_unClicked) { 
                    up.setImageDrawable(up_clicked);
                    ratingValue = ratingValue + 1;
                    ratingString = Integer.toString(ratingValue);
                    ratingView.setText(ratingString);           
                    post.setRating(ratingString);                   
                    wsAsync = new WebServiceAsync(context);
                    wsAsync.execute(voteTag, postID, "up");                     
                // else the post is voted up...
                } else {
                    up.setImageDrawable(up_unClicked);
                    ratingValue = ratingValue - 1;
                    ratingString = Integer.toString(ratingValue);
                    ratingView.setText(ratingString);
                    post.setRating(ratingString);
                    wsAsync = new WebServiceAsync(context);
                    wsAsync.execute(voteTag, postID, "down");
                }                           
            // else the post is voted down...
            } else {
                down.setImageDrawable(down_unClicked);
                up.setImageDrawable(up_clicked);
                ratingValue = ratingValue + 2;
                ratingString = Integer.toString(ratingValue);
                ratingView.setText(ratingString);
                post.setRating(ratingString);
                wsAsync = new WebServiceAsync(context);
                wsAsync.execute(voteTag, postID, "upDownAlready");
            }
        }
    });

    holder.ratingDown.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View convertView) {

            // get post details using button tag
            int pos = (Integer)convertView.getTag();
            Post post = cityFeed.get(pos);
            String postID = post.getPostID();
            String ratingString = post.getRating();
            int ratingValue = Integer.parseInt(ratingString);               
            RelativeLayout parent = (RelativeLayout)convertView.getParent().getParent();
            TextView ratingView = (TextView)parent.findViewById(R.id.rating);
            ImageButton up = (ImageButton)parent.findViewById(R.id.ratingUp);
            ImageButton down = (ImageButton)parent.findViewById(R.id.ratingDown);

            // if the post is not voted up...
            if (up.getDrawable() == up_unClicked) {             
                // if the post is not voted down...
                if (down.getDrawable() == down_unClicked) { 
                    down.setImageDrawable(down_clicked);
                    ratingValue = ratingValue - 1;
                    ratingString = Integer.toString(ratingValue);
                    ratingView.setText(ratingString);           
                    post.setRating(ratingString);                   
                    wsAsync = new WebServiceAsync(context);
                    wsAsync.execute(voteTag, postID, "down");                       
                // else the post is voted down...
                } else {
                    down.setImageDrawable(down_unClicked);
                    ratingValue = ratingValue + 1;
                    ratingString = Integer.toString(ratingValue);
                    ratingView.setText(ratingString);
                    post.setRating(ratingString);
                    wsAsync = new WebServiceAsync(context);
                    wsAsync.execute(voteTag, postID, "up");
                }                           
            // else the post is voted up...
            } else {
                up.setImageDrawable(up_unClicked);
                down.setImageDrawable(down_clicked);
                ratingValue = ratingValue - 2;
                ratingString = Integer.toString(ratingValue);
                ratingView.setText(ratingString);
                post.setRating(ratingString);
                wsAsync = new WebServiceAsync(context);
                wsAsync.execute(voteTag, postID, "downUpAlready");
            }
        }
    });
    return convertView;
}
1

There are 1 answers

1
Mukesh Rana On BEST ANSWER

By considering that your onClickListerners(on holder.ratingUp and holder.ratingDown) works fine, i think the problem is in this portion of your code

if (userVotesUp.contains(postID)) {
    holder.ratingUp.setImageDrawable(up_clicked);
} else if (userVotesDown.contains(postID) && userVotesUp != null) {
    holder.ratingDown.setImageDrawable(down_clicked);
} else {
    holder.ratingUp.setImageDrawable(up_unClicked);
    holder.ratingDown.setImageDrawable(down_unClicked);
}

If i am not wrong, you are doing something like that you have 3 conditions, First is

if (userVotesUp.contains(postID)) 

that means rating is upvoted and you are setting up_clicked imageDrawable, but you are not setting down_unClicked image drawable to holder.ratingDown.

second condition applies to this

if (userVotesUp.contains(postID)) 

then you are setting down_clicked drawable to holder.ratingDown, but not setting up_unClicked image drawable to holder.ratingUp.

and third condition is neither upvoted nor downvoted and that seems to be fine. so I think, you have to replace your that portion of code with this

if (userVotesUp.contains(postID)) {
    holder.ratingUp.setImageDrawable(up_clicked);
    holder.ratingDown.setImageDrawable(down_unClicked);
} else if (userVotesDown.contains(postID) && userVotesUp != null) {
    holder.ratingDown.setImageDrawable(down_clicked);
    holder.ratingUp.setImageDrawable(up_unClicked);
} else {
    holder.ratingUp.setImageDrawable(up_unClicked);
    holder.ratingDown.setImageDrawable(down_unClicked);
}

Hope this helps..!!