RecyclerView 在旋转时丢失状态

RecyclerView loses state on rotation

我正在使用 MVVM 设计模式制作一个笔记应用程序,Room for persisting data and paging

问题是当我旋转我的设备时,它似乎保持其状态不到一秒钟,然后 RecyclerView 向上滚动 我调试了我的代码,发现 onChanged() 被多次调用

这是我的代码

NoteRepository

override fun loadPagedNotes() : LiveData<PagedList<Note>> {
       val factory : DataSource.Factory<Int, Note> = mNotesDao.getNotes()
       val mNotesList = MutableLiveData<PagedList<Note>>()

       val notesList = RxPagedListBuilder(
           factory, PagedList.Config
               .Builder()
               .setPageSize(20)
               .setEnablePlaceholders(true)
               .build()
       ).buildFlowable(BackpressureStrategy.LATEST)

       mDisposables.add(
           notesList.subscribeOn(Schedulers.io())
               .observeOn(AndroidSchedulers.mainThread())
               .subscribe {
                   mNotesList.value = it
               }
       )
       return mNotesList
   }

NoteViewModel

fun loadPagedNotes() : LiveData<PagedList<Note>> {
        return mNoteRepository.loadPagedNotes()
    }

HomeActivity

class HomeActivity : AppCompatActivity() {

    private lateinit var mBinding : ActivityHomeBinding
    private val mViewModel : NoteViewModel by viewModel()

    override fun onCreate(savedInstanceState : Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_home)
        loadNotes()
    }


    private fun loadNotes() {
        mViewModel.loadPagedNotes()
            .observe(this,
                Observer {
                    if (it.isNotEmpty()) {
                        addNotesToRecyclerView(it)
                    }
                })
    }

    private fun addNotesToRecyclerView(list : PagedList<Note>?) {
        showRecyclerView()
        val adapter = PagedNoteListAdapter(this@HomeActivity)
        adapter.submitList(list)
        mBinding.notesRecyclerView.adapter = adapter
    }
}

我不是 RxJava 专家所以我不能说太多但是你有没有尝试从 ViewModelProviders class 获取你的 ViewModel 而不是:

myViewModel = ViewModelProviders.of(this)[MyViewModel::class.java]

我相信以这种方式创建 ViewModel 实例允许您的 ViewModel 存在于您的 Activities 生命周期之外,并且可能有助于解决您的状态问题。

当您旋转设备时,视图(片段)会被销毁并重新创建,但 ViewModel 仍然存在。您 运行 遇到了麻烦,因为您的 ViewModel 从不利用此功能:相反,在(重新)创建您的视图时,它会导致 ViewModel 再次重新获取数据。每次调用 VM 的 loadPagedNotes 都会创建一个新的 LiveData 并 return 它。您真的希望只有一个并且 return 每次都引用那个。

你为什么不把你的代码改成这样

class NoteViewModel: ViewModel() {
    val pagedNotes = mNoteRepository.loadPagedNotes()
}

在你的 activity

override fun onCreate(/*...*/) {
    mViewModel.pagedNotes.observe(this, Observer { addNotesToRecyclerView(it) 
})

此外,考虑将此 val adapter = PagedNoteListAdapter(this@HomeActivity) 移动到 Activity 的实例成员:val mAdapter = ...。这样,您的 addNotesToRecyclerView 代码将不会在您的存储库每次有更新时创建和绑定新的适配器。

class HomeActivity: /*...*/ {
    val mAdapter = PagedNoteListAdapter(this)

    override fun onCreate(...) {
        ...
        mBinding.notesRecyclerView.adapter = mAdapter
    }

    private fun addNotesToRecyclerView(list: PagedList<Note>) // You don't need the question mark since you're never calling the function except when you already know `list` isn't null) {
        mAdapter.submitList(list)
}

这可能是您遇到这种情况的另一个原因。

此外,如果您仍然有不满意的刷新,请查看 DiffUtil。它使您能够在适配器的项目单独更改时更新它们,因此即使整个列表发生更改但某些元素保持不变,您也只会重绘已更改的元素而不会重绘未更改的元素(例如,如果您添加了一项新项目,它不会重绘所有内容,而只会绘制一项新项目)