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
相关产品推荐
相关产品推荐

