RecyclerView滚动后数据丢失问题求助(适配Android 11/12/13)
解决RecyclerView滚动数据丢失/错位问题(Android 12/13)
核心问题根源
你遇到的问题本质是RecyclerView的ViewHolder复用机制与Adapter绑定逻辑不匹配。低版本Android的RecyclerView复用策略相对宽松,没暴露逻辑漏洞;但Android 12/13对复用机制做了优化,更频繁地复用ViewHolder,直接放大了“UI状态未与数据源同步”的问题。之前尝试的setHasStableIds(true)、禁用复用等方法都是治标不治本,核心要修正Adapter的绑定逻辑。
必须执行的修复步骤
1. 强制UI状态完全依赖数据源
所有条目的数据(包括用户输入的内容)必须实时同步到你的数据集(比如List<YourDataModel>),不能只存放在ViewHolder的EditText/TextView等视图中。
- 示例:用户在EditText输入时,通过
TextWatcher把输入值同步到对应的数据模型:holder.inputEt.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { // 直接更新数据源对应位置的字段 mDataList.get(holder.getAdapterPosition()).setInputContent(s.toString()); } });
2. 所有UI绑定逻辑必须放在onBindViewHolder中
不要在onCreateViewHolder中设置与数据相关的内容或监听,所有条目级的UI赋值、事件监听都要在onBindViewHolder中完成,且每次绑定都要覆盖旧状态:
- 错误示例:只在
onCreateViewHolder中给EditText设置初始值,复用ViewHolder时不会更新为最新数据。 - 正确示例:
@Override public void onBindViewHolder(MyViewHolder holder, int position) { YourDataModel item = mDataList.get(position); // 每次绑定都重新设置文本,覆盖复用带来的旧数据 holder.inputEt.setText(item.getInputContent()); // 注意:绑定监听前要先移除旧监听,避免重复触发 holder.inputEt.removeTextChangedListener(holder.textWatcher); holder.textWatcher = new TextWatcher() { // 实现监听逻辑,同步数据源 }; holder.inputEt.addTextChangedListener(holder.textWatcher); }
3. 正确使用通知更新方法
修改数据源后,必须调用对应的notifyXXX方法通知Adapter更新,禁止直接操作ViewHolder视图:
- 添加条目:
notifyItemInserted(position) - 修改条目:
notifyItemChanged(position) - 避免使用
notifyDataSetChanged()(全量更新效率极低,且可能引发额外复用问题)
4. 禁用错误的“规避复用”操作
holder.setIsRecyclable(false)会完全禁用ViewHolder复用,导致内存占用飙升,高版本系统下可能触发内存警告甚至崩溃,绝对不能用。setHasStableIds(true)仅当你的数据有唯一且永不改变的ID时才有用,否则只会增加额外开销。
针对Android 12/13的额外检查
高版本系统中,RecyclerView的RecycledViewPool会更高效地复用ViewHolder,需确保:
- 数据模型类的
equals/hashCode方法正确实现(如果用到DiffUtil的话) - 不要在Adapter之外保存ViewHolder的引用,避免外部修改UI导致状态混乱
内容的提问来源于stack exchange,提问作者mohinuddeen
相关产品推荐
相关产品推荐

