RecyclerView屏幕旋转后滑动功能失效及引入LiveData后崩溃问题求解
问题解答
1. 修复屏幕旋转后滑动功能失效不需要使用LiveData
屏幕旋转后项视图类型无法更新的原因是:屏幕旋转会触发Activity/Fragment销毁重建,你之前保存在Adapter内存中的historyData列表(每个条目携带的showMenu状态)会随旧实例销毁丢失,重建时你直接从数据库读取的HistoryObject默认showMenu都为false,同时重建后的Adapter是全新实例,和之前滑动手势绑定的实例不匹配,所以就算滑动事件正常触发,也无法更新新列表的状态、切换视图类型。
2. 你当前ViewModel实现的错误点
直接导致崩溃的原因
你在MainActivity的onCreate方法中每次重建都会执行historyViewModel.setHistoryList(mutableListOf()),将ViewModel中的列表强制重置为空。屏幕旋转后Activity重建先触发这个操作,LiveData会先发射空列表,此时Fragment的观察回调用空列表创建了Adapter和滑动助手,滑动时访问索引0就会触发IndexOutOfBoundsException。
其他导致功能异常的问题
- 你每次收到LiveData的列表更新时都会调用
refreshRecyclerView重新创建Adapter、重新绑定ItemTouchHelper,这一操作完全没有必要,反复创建实例会导致状态不同步。 - ViewModel仅存储了列表的原始数据,没有持久化每个条目的
showMenu状态,每次从数据库拉取的新对象默认都为关闭菜单状态,就算用了ViewModel,旋转后滑动展开的菜单状态依然会丢失。
修复方案
- 删除
MainActivityonCreate中清空ViewModel列表的historyViewModel.setHistoryList(mutableListOf())代码。 - 将Adapter和ItemTouchHelper改为Fragment的成员变量,仅在
onViewCreated中初始化一次,后续LiveData收到新列表时,仅更新Adapter内部的historyData数据源,调用notifyDataSetChanged()或用DiffUtil做差分更新即可。 - 如果需要持久化菜单展开状态,要么将
showMenu字段存入数据库,要么更新ViewModel列表时保留已有条目的showMenu状态,不要直接用数据库拉取的新对象全量覆盖。
内容的提问来源于stack exchange,提问作者Daniel Bank
相关产品推荐
相关产品推荐

