toggle button changed its state when scrolled in RecyclerView with mysqlite database

2.1k views Asked by At

Here is my code

@Override
public void onBindViewHolder(final RecyclerViewHolder holder, int position) {
final Songs songs = arrayList.get(position);

holder.favorite.setChecked(songs.getFavorite()); // this line makes me confusing.

   holder.favorite.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
         int r =  db.update_favorite(b,songs.getTitle(),songs.getArtist());

            compoundButton.setChecked(b);
        }
    });

}

the problem here is if i include this code

holder.favorite.setChecked(songs.getFavorite());

to onBindViewHolder, when I change the state of toggle button and scroll down then scroll up, the state of toggle button was change itself to original state. To clarify, when toggle button state change into true from false and the user scroll down and up, the toggle button automatically change into original state which is to false.

how to make the toggle button holds the changes of state even the user scroll down? please help me.

3

There are 3 answers

3
Ben P. On BEST ANSWER

Here's my guess: the CompoundButton.OnCheckedChangeListener is firing at a time you're not expecting.

Imagine you have 100 songs, each of which starts out as not a favorite. You activate the CompoundButton associated with song #5, which triggers its OnCheckedChangeListener and marks song #5 as a favorite in your database. Then you scroll down until song #5 isn't on screen anymore.

At some point, the ViewHolder that was previously associated with song #5 is going to be recycled, and then re-used to display another song. At that point in time, onBindViewHolder() will be called. And that will trigger this line:

holder.favorite.setChecked(songs.getFavorite());

Remember, this ViewHolder used to be associated with song #5, so the CompoundButton is checked before this line runs. Since the new song is not a favorite, this line will change the CompoundButton so that it is unchecked.

This will trigger the onCheckedChangeListener. Except at this point, the listener hasn't yet been reassigned and so still refers to song #5. Since the CompoundButton was changed from checked to unchecked, the listener will mark song #5 as not a favorite in your database.

Then the listener is reassigned and now refers to the new song. But at this point, the damage is already done.

You could solve this by simply adding

holder.favorite.setOnCheckedChangeListener(null);

at the beginning of onBindViewHolder().

0
Kerelos On

Also It solved for me after adding the below method to the adapter:

@Override
public int getItemViewType(int position) {

    return position;
}
0
Tajveer Singh Nijjar On

Ben P. has beautifully explained the reason for the problem. Just want to add something to the solution.

Instead of listening to check change event on the switch, listen to the click event. On a switch, check event can be triggered on a number of other reasons. But click will be triggered only when the user clicks on the switch.

Hope I am able to explain the things properly.

Thanks.