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

如何在设备旋转时保存RecyclerView.Adapter的数据?

解决RecyclerView拖拽排序后配置变化丢失排序的问题

看起来你遇到的核心痛点是:onSaveInstanceState 的存储容量有限,没法存大量的 AppData 对象,导致旋转屏幕或Activity销毁重建后,辛苦拖拽好的排序直接丢失了。下面给你几个实用的解决方案,按场景优先级排序:

方案1:用ViewModel保留数据(最适合配置变化场景)

ViewModel的生命周期完全独立于Activity的配置变化(比如旋转屏幕),只要把你的数据List放在ViewModel里,旋转时数据不会被销毁重建,自然就能保留排序状态。

具体步骤:

  1. 先创建一个继承自ViewModel的类,专门用来持有你的数据:
class AppDataViewModel : ViewModel() {
    // 用MutableLiveData是为了数据变化时能自动通知UI更新,也可以直接用MutableList
    val appDataList = MutableLiveData<MutableList<AppData>>()

    // 初始化数据的方法,避免重复加载
    fun initData(initialList: MutableList<AppData>) {
        if (appDataList.value.isNullOrEmpty()) {
            appDataList.value = initialList
        }
    }
}
  1. 在你的Activity/Fragment中获取ViewModel实例,用它来管理所有数据操作:
class YourActivity : AppCompatActivity() {
    private lateinit var viewModel: AppDataViewModel
    private lateinit var adapter: YourAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 获取ViewModel实例
        viewModel = ViewModelProvider(this)[AppDataViewModel::class.java]

        // 初始化数据:如果ViewModel里没有数据,就从原始来源加载(比如本地资源、网络)
        val initialData = loadInitialAppData()
        viewModel.initData(initialData)

        // 观察数据变化,自动更新Adapter
        viewModel.appDataList.observe(this) { sortedList ->
            adapter.submitList(sortedList)
        }

        // 初始化RecyclerView和拖拽功能
        adapter = YourAdapter(viewModel.appDataList.value ?: mutableListOf())
        recyclerView.adapter = adapter
        setupDragAndDrop()
    }

    // 拖拽交换位置时,直接操作ViewModel里的List
    private fun onItemDragged(fromPosition: Int, toPosition: Int) {
        val currentList = viewModel.appDataList.value ?: return
        Collections.swap(currentList, fromPosition, toPosition)
        viewModel.appDataList.postValue(currentList) // 通知UI刷新
    }
}

这样旋转屏幕时,ViewModel会稳稳保留住排序后的List,Activity重建后直接复用ViewModel里的数据,排序自然不会丢。

方案2:本地持久化(适合需要长期保存排序的场景)

如果不仅是配置变化,连APP重启后都想保留排序,那就要把排序状态持久化到本地。推荐用Room数据库,也可以用SharedPreferences(适合数据量不大的情况)。

用Room的示例:

  1. 修改AppData为Room实体类,增加一个sortOrder字段记录排序位置:
@Entity(tableName = "app_data")
data class AppData(
    @PrimaryKey val id: String, // 每个元素要有唯一ID,比如UUID生成
    val title: String,
    val desc: String,
    val drawableResId: Int, // 注意:Drawable不能直接存数据库,建议存资源ID
    var sortOrder: Int // 专门用来记录排序位置的字段
)
  1. 拖拽交换位置后,更新所有受影响元素的sortOrder,并同步到数据库:
private fun onItemDragged(fromPosition: Int, toPosition: Int) {
    val currentList = adapter.currentList.toMutableList()
    Collections.swap(currentList, fromPosition, toPosition)
    
    // 更新每个元素的排序字段
    currentList.forEachIndexed { index, appData ->
        appData.sortOrder = index
    }
    
    // 批量更新到数据库(用Room的批量更新方法)
    viewModel.updateAppDataList(currentList)
    adapter.submitList(currentList)
}
  1. 每次启动APP或Activity重建时,从数据库按sortOrder升序加载数据:
viewModel.getSortedAppData().observe(this) { sortedList ->
    adapter.submitList(sortedList)
}

这样不管是旋转屏幕还是重启APP,排序都会从数据库加载,完全不会丢失。

方案3:只保存排序索引(适合数据量较大但不需要长期保存的场景)

如果不想用ViewModel,也不想引入数据库,可以只保存每个元素的唯一标识的排序顺序,而不是整个AppData对象。这样存储的数据量极小,甚至可以存在onSaveInstanceState里。

具体步骤:

  1. 给AppData增加一个唯一标识字段:
data class AppData(
    val id: String, // 唯一ID,比如用UUID.randomUUID().toString()生成
    val field1: String,
    val field2: String,
    val icon: Drawable
)
  1. 在onSaveInstanceState中保存排序后的ID列表:
override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    val sortedIds = adapter.currentList.map { it.id }
    outState.putStringArrayList("sorted_ids", ArrayList(sortedIds))
}
  1. 在onCreate中恢复排序:
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val initialData = loadInitialAppData()
    var sortedData = initialData

    // 如果有保存的排序ID,重新对原始数据排序
    savedInstanceState?.getStringArrayList("sorted_ids")?.let { sortedIds ->
        sortedData = sortedIds.mapNotNull { id ->
            initialData.find { it.id == id }
        }.toMutableList()
    }

    // 初始化Adapter和RecyclerView
    adapter = YourAdapter(sortedData)
    recyclerView.adapter = adapter
    setupDragAndDrop()
}

这个方法的好处是存储的数据量极小,完全符合onSaveInstanceState的限制,但缺点是如果原始数据发生变化(比如新增/删除元素),排序可能会出错,适合数据固定的场景。


总结一下:

  • 只是应对旋转屏幕等配置变化:优先用ViewModel,最简单高效。
  • 需要长期保存排序(重启APP也不丢):用Room数据库,持久化最可靠。
  • 数据量大但只需要临时保存排序:用保存排序索引的方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:04:26