0

我创建了一个自定义listadapter其中包含三个组件歌曲标题、歌曲编号和收藏图标。收藏图标用于标记或取消标记列表中的收藏项。请查看随附的视频以了解问题所在。

视频

当我点击星星时,图标会被选中/取消选中并触发setOnFavoriteChangeListener事件。如果我检查isFavorite状态并相应地更新数据库。这是适配器的完整代码:

public class song_index_adapter extends ArrayAdapter<song_index_model>{ //implements View.OnClickListener {
private ArrayList<song_index_model> dataSet;
Context mContext;
private int lastPosition = -1;

public song_index_adapter(ArrayList<song_index_model> data, Context context) {
    super(context, R.layout.song_index_row, data);
    this.dataSet = data;
    this.mContext=context;
}
// View lookup cache
private static class ViewHolder {
    TextView txt_sno;
    TextView txt_title;
    MaterialFavoriteButton favorite;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
    // Get the data item for this position
    final song_index_model dataModel = getItem(position);

    // Check if an existing view is being reused, otherwise inflate the view
    final ViewHolder viewHolder; // view lookup cache stored in tag

    final View result;

    if (convertView == null) {
        viewHolder = new ViewHolder();
        LayoutInflater inflater = LayoutInflater.from(getContext());
        convertView = inflater.inflate(R.layout.song_index_row, parent, false);

        viewHolder.txt_sno = (TextView) convertView.findViewById(R.id.sno);
        viewHolder.txt_title = (TextView) convertView.findViewById(R.id.songTitle);
        viewHolder.favorite = (MaterialFavoriteButton) convertView.findViewById(R.id.indexfav);

        result=convertView;

        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
        result=convertView;
    }

    Animation animation = AnimationUtils.loadAnimation(mContext, (position > lastPosition) ? R.anim.up_from_bottom : R.anim.down_from_top);
    result.startAnimation(animation);
    lastPosition = position;

    viewHolder.txt_sno.setText(dataModel.getSno());
    viewHolder.txt_title.setText(dataModel.getTitle());

    //--- following conditional statements take care to
    //--- not to show a star with the index letter
    if(viewHolder.txt_sno.getText().toString().equals(""))
        viewHolder.favorite.setVisibility(View.GONE);
    else
        viewHolder.favorite.setVisibility(View.VISIBLE);

    viewHolder.favorite.setFavorite(dataModel.getFav());

    int fsize = (gvar.fontsize * gvar.fontstep) + gvar.fontmin;
    viewHolder.txt_title.setTextSize(fsize);
    viewHolder.txt_sno.setTextSize(fsize);

    viewHolder.favorite.setOnFavoriteChangeListener(new MaterialFavoriteButton.OnFavoriteChangeListener() {
        @Override
        public void onFavoriteChanged(MaterialFavoriteButton buttonView, boolean isfavorite) {
            DBHelper db = new DBHelper(mContext);
            SQLiteDatabase sdb = db.getWritableDatabase();

            boolean isUpdate = db.updateData(gvar.table,dataModel.getSno(),dataModel.getTitle(),dataModel.getSong(),dataModel.getCategory(),isfavorite);
            if(!isUpdate)
                Toast.makeText(mContext, "Song Selection could not be saved", Toast.LENGTH_SHORT).show();
            else {
                Toast.makeText(mContext, "Updated " + dataModel.getSno(), Toast.LENGTH_SHORT).show();
                Log.e("UPDATED", dataModel.getSno() + " " + isfavorite);
            }
        }
    });
    return convertView;
}

}

该事件在adapter设置的文件中listview,它基本上检查最喜欢的明星的状态并更新数据库中歌曲的状态。您可以看到Toast提示有关更新的消息。

我的问题是,即使我只是向上和向下滚动而不按星形图标,setOnFavoriteChangeListener事件也会继续触发。这可以在Toast消息和Log记录中看到。我附上日志记录的快照也供您查看。 日志记录

我个人更改了最喜欢的图标,只有开头的第 9 和第 42 首歌曲和最后的第 35 首歌曲。在这两者之间,我只不断向上和向下滚动,您可以看到 UPDATE 是如何自行发生的。

我的目标是标记最喜欢的项目列表。

为什么在setOnFavoriteChangeListener我不碰它的情况下被解雇。

有没有其他方法可以从列表中标记最喜欢的项目并将它们保存在数据库中。

提前致谢

4

1 回答 1

0

我想我发现了你的问题。这与您正在回收 ListView 的项目有关。在初始加载期间,一切正常,没有选择任何内容,调用 dataModel.getFav() 返回 false,因此当您调用 viewHolder.favorite.setFavorite() 时,MaterialFavoriteButton 不会触发,它设置为 OnFavoriteChangeListener。这样做的原因是,因为在内部它会检查新收藏的状态是否与上一个不同,以防止不必要的工作(我检查了源代码)。但是,一旦您做出选择,您的 onFavoriteChanged 将被触发,因为新状态不同,然后您将值存储在数据库中。当您开始滚动时会出现问题,因为您的视图被回收,MaterialFavoriteButton 的收藏状态将设置,但是当您调用 dataModel.getFav() 时,它将返回 false 并将 MaterialFavoriteButton 的收藏状态更改回 false。从而导致您的 MaterialFavoriteButton 的旧 OnFavoriteChangeListener 再次触发(因此按钮不被收藏)。它还使用以前的 dataModel 更新您的数据库(注意:这是一个关闭问题)这就是为什么您看到它使用屏幕滚动视图中的文本。调用旧 OnFavoriteChangeListener 的原因是视图正在被回收,并且仍然具有您在初始加载期间传递给它的实例。因此,一旦填充了所有视图以填充整个屏幕,如果您滚动第一个离开顶部屏幕的视图将作为 convertView 传递给 getView()。您应该将调用 viewHolder.favorite.setOnFavoriteChangeListener 移动到 setFavorite( ) 称呼。如果你在代码中放置一个调试语句并逐步调用 viewHolder.favorite.setFavorite() 你应该明白我在说什么。我希望这一切都对你有所帮助。如果没有,请发表评论,我会尝试为您提供更多帮助。我推荐的解决方案是推迟数据库写入,直到按下保存按钮或 Activity/Fragment 暂停或停止,并将最喜欢的状态存储在使用 getView(...) 位置参数访问的 ArrayList 中. 这更有效,因为您不必在 ListView 滚动的任何时候不断地访问数据库。

于 2017-10-20T14:31:30.880 回答