You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RecyclerView Adapter删除SharedPreferences项后列表未即时刷新

问题根因

notifyDataSetChanged() 调用后列表不刷新的核心原因是:你仅更新了SharedPreferences中的持久化数据,没有同步修改Adapter持有的内存数据源allBooksActivityModels。
RecyclerView的渲染完全依赖Adapter内部维护的内存列表,SP里的数据修改后,内存里的列表仍保留着待删除条目,调用刷新方法时还是用旧数据渲染,自然看不到变化;退出Activity重进时,页面会重新从SP读取数据初始化Adapter的数据源,这时候才会加载到删除后的最新列表,所以才会出现重进才刷新的现象。
另外你现有代码还有几个隐藏问题:

  • for-each遍历ArrayList时直接调用remove()删除元素,会触发ConcurrentModificationException崩溃
  • 点击事件里直接用外部传入的固定position值,列表滑动或增删条目时容易出现角标错位、删错条目的问题
  • 你贴的SP删除方法名为RemoveFromWantToRead,但点击事件里调用的是RemoveFromCurrenlyReading,要确认调用的是对应列表的删除方法,避免操作错SP存储的key
修复步骤

1. 优化SP删除方法,修复遍历删除崩溃问题

不要在for-each循环里直接删列表元素,改用迭代器遍历,同时去掉多余的key移除操作,直接put新值覆盖即可,非同步场景用apply()代替commit()提升性能:

public boolean RemoveFromWantToRead(AllBooksActivityModel book) {
    ArrayList<AllBooksActivityModel> books = getWantToReadBooks();
    if (books == null || books.isEmpty()) {
        return false;
    }
    Iterator<AllBooksActivityModel> iterator = books.iterator();
    while (iterator.hasNext()) {
        AllBooksActivityModel b = iterator.next();
        if (b.getBookID() == book.getBookID()) {
            iterator.remove();
            Gson gson = new Gson();
            SharedPreferences.Editor editor = sharedPreferences.edit();
            // 直接put覆盖原key即可,不需要先remove
            editor.putString(WANT_TO_READ_BOOKS, gson.toJson(books));
            editor.apply();
            return true;
        }
    }
    return false;
}

如果你是在“正在阅读”列表做删除,就把对应RemoveFromCurrenlyReading方法做同样的遍历逻辑修改。

2. 删除成功后同步更新Adapter内存数据源

SP删除成功后,先移除内存列表里对应位置的条目,再做局部刷新,不要直接调用全局刷新:

holder.BtnDltTxt.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setMessage("确定要删除这条记录吗?");
        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                // 获取实时位置,避免position错位
                int currentPos = holder.getAdapterPosition();
                if (currentPos == RecyclerView.NO_POSITION) return;
                
                AllBooksActivityModel targetBook = allBooksActivityModels.get(currentPos);
                String bookName = targetBook.getBookName();
                if(Ulitls.getInstance(context).RemoveFromCurrenlyReading(targetBook)){
                    Toast.makeText(context, bookName + " 已删除", Toast.LENGTH_SHORT).show();
                    // 核心:先移除内存数据源中的对应条目
                    allBooksActivityModels.remove(currentPos);
                    // 局部刷新,性能优于全局notifyDataSetChanged,自带系统默认删除动画
                    notifyItemRemoved(currentPos);
                    // 刷新后续条目位置,避免角标错位
                    notifyItemRangeChanged(currentPos, allBooksActivityModels.size());
                }else{
                    Toast.makeText(context, "删除失败,请重试", Toast.LENGTH_SHORT).show();
                }
            }
        });
        builder.setNegativeButton("取消", null);
        builder.create().show();
    }
});
优化建议
  • 单条条目增删场景优先用notifyItemRemoved/notifyItemInserted这类局部刷新方法,比全局notifyDataSetChanged性能更高,还能自带系统默认的列表动画,交互体验更好
  • SharedPreferences没有强同步提交需求时,优先用apply()而非commit(),前者是异步写入磁盘,不会阻塞主线程
  • 所有需要拿条目位置的点击事件里,不要用匿名内部类捕获的固定position,统一用holder.getAdapterPosition()获取实时位置,避免滑动、增删后位置错乱

内容的提问来源于stack exchange,提问作者Shanuka_N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 05:39:39