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。它使您能够在适配器的项目单独更改时更新它们,因此即使整个列表发生更改但某些元素保持不变,您也只会重绘已更改的元素而不会重绘未更改的元素(例如,如果您添加了一项新项目,它不会重绘所有内容,而只会绘制一项新项目)
我正在使用 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。它使您能够在适配器的项目单独更改时更新它们,因此即使整个列表发生更改但某些元素保持不变,您也只会重绘已更改的元素而不会重绘未更改的元素(例如,如果您添加了一项新项目,它不会重绘所有内容,而只会绘制一项新项目)