使用 sqlite 数据库在 RecyclerView 中滚动时,切换按钮会更改其状态

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

这是我的代码

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

}

这里的问题是如果我包含这段代码

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

onBindViewHolder,当我更改切换按钮的状态并向下滚动然后向上滚动时,切换按钮的状态会自行更改为原始状态。澄清一下,当切换按钮状态从 false 变为 true 并且用户向下和向上滚动时,切换按钮会自动变为原始状态,即 false。

如何让切换按钮保持状态的变化,即使用户向下滚动?请帮助我。

这是我的猜测:CompoundButton.OnCheckedChangeListener 在您意想不到的时间触发。

假设您有 100 首歌曲,每首歌曲开始时都不受欢迎。您激活与歌曲 #5 关联的 CompoundButton,这会触发它的 OnCheckedChangeListener 并将歌曲 #5 标记为您数据库中的最爱。然后向下滚动,直到歌曲 #5 不再出现在屏幕上。

在某些时候,之前与歌曲 #5 关联的 ViewHolder 将被回收,然后 re-used 显示另一首歌曲。届时,将调用 onBindViewHolder()。这将触发这条线:

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

请记住,此 ViewHolder 曾经与歌曲 #5 相关联,因此 CompoundButton 在该行运行之前被 选中 。由于新歌 不是 最喜欢的,此行将 更改 CompoundButton 以便取消选中。

这将触发 onCheckedChangeListener. 但此时听众尚未重新分配,因此仍引用歌曲 #5。由于 CompoundButton 已从选中更改为未选中,听众会将歌曲 #5 标记为 您数据库中的收藏夹。

然后听众被重新分配,现在指的是新歌。但此时,伤害已经造成。

你可以通过简单地添加

来解决这个问题
holder.favorite.setOnCheckedChangeListener(null);

onBindViewHolder()开头。

Ben P. 很好地解释了问题的原因。只是想在解决方案中添加一些内容。

不要在开关上监听 check change 事件,而是监听 click 事件。在 switch 上,check 事件可以因许多其他原因而被触发。但是click只有在用户点击switch的时候才会触发。

希望我能够正确解释这些事情。

谢谢。

在适配器中添加以下方法后,它也为我解决了:

@Override
public int getItemViewType(int position) {

    return position;
}