Android 在使用MVVM viewmodel和livedata时,如何在配置更改后保留RecyclerView的滚动位置?

Android 在使用MVVM viewmodel和livedata时,如何在配置更改后保留RecyclerView的滚动位置?,android,mvvm,android-recyclerview,viewmodel,android-livedata,Android,Mvvm,Android Recyclerview,Viewmodel,Android Livedata,首先阅读: 抱歉,我好像玩了我自己。早些时候,我在xml中使用了RecyclerView,但将其转换为(它仍然使用完全相同的RecyclerView适配器)。如果我切换回RecyclerView,下面的原始代码会起作用-滚动位置会在配置更改时自动保存和恢复。 我使用的是一个MVVM viewmodel类,它在配置更改后成功地保留了RecyclerView的列表数据。但是,不会恢复以前的RecyclerView位置。这是预期的行为吗?解决这个问题的好办法是什么 我看到一个简短的例子,您可以通过在R

首先阅读: 抱歉,我好像玩了我自己。早些时候,我在xml中使用了RecyclerView,但将其转换为(它仍然使用完全相同的RecyclerView适配器)。如果我切换回RecyclerView,下面的原始代码会起作用-滚动位置会在配置更改时自动保存和恢复。

我使用的是一个MVVM viewmodel类,它在配置更改后成功地保留了RecyclerView的列表数据。但是,不会恢复以前的RecyclerView位置。这是预期的行为吗?解决这个问题的好办法是什么

我看到一个简短的例子,您可以通过在RecyclerView上设置适配器之前设置适配器数据来保持滚动位置。 据我所知,在配置更改之后,前面观察到的livedata会得到回调。这个回调是我设置适配器数据的地方。但是这个回调似乎发生在onCreate()函数完成之后,此时我的RecyclerView适配器已经设置好了

class MainActivity:AppCompatActivity(){
private val adapter=MovieAdapter()
私有lateinit变量viewModel:MainViewModel
重写创建时的乐趣(savedInstanceState:Bundle?){
super.onCreate(savedInstanceState)
val绑定=活动主绑定。充气(平放)
setContentView(binding.root)
//创建或检索viewmodel并观察recyclerview所需的数据
viewModel=ViewModelProvider(this.get)(MainViewModel::class.java)
viewModel.movies.observe(这个{
adapter.items=it
})
binding.recyclerview.adapter=适配器
//如果viewmodel没有recyclerview的数据,请检索它
如果(viewModel.movies.value==null)viewModel.retrieveMovies()
}
}
class电影适配器:
RecyclerView.Adapter(){
变量项:按委托列出。可观察(emptyList()){{uu,{uu,}->
notifyDataSetChanged()
}
类MovieViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
private val binding=ItemMovieCardBinding.bind(itemView)
趣味绑定(项目:电影){
有(约束力){
imagePoster.load(item.posterUrl)
textRating.text=item.rating.toString()
textDate.text=item.date
textOverview.text=item.overview
}
}
}
重写CreateViewHolder(父级:ViewGroup,viewType:Int):MovieViewHolder{
val view=LayoutInflater.from(parent.context)
.充气(R.layout.item\u movie\u卡,父级,假)
返回MovieViewHolder(视图)
}
覆盖BindViewHolder(holder:MovieViewHolder,位置:Int){
持有者绑定(项目[位置])
}
重写getItemCount()=items.size
}
class MainViewModel:ViewModel(){
private val_movies=MutableLiveData()
val movies:LiveData get()=\u movies
有趣的电影{
viewModelScope.launch{
val client=ApiClient.create()
val结果:Movies=withContext(Dispatchers.IO){client.getPopularMovies()}
_movies.value=result.movies
}
}
}

仅在适配器项目可用后设置适配器

    viewModel.movies.observe(this, {
        adapter.items = it
        binding.recyclerview.adapter = adapter
    })

这是预期的行为吗?
配置更改将重新创建整个活动,它将通过onDestroy,然后是onCreate,这意味着它是您拥有的新活动,因此是预期的或正常的。这是你真的必须“修复”的东西吗?这取决于你。你会怎么修理它?我不确定:)如果你找到一种可靠的方法来保存最后一个可见的项目,你可能会使用smoothScrollToPosition,或者类似的东西在你的
observe()
lambda中,有
adapter.items=it
。设置项目时,
MovieAdapter
做什么?它是否调用了notifyDataSetChanged()?你能用适配器的相关代码更新问题吗?@a_local_nobody根据上述博客:“有几种方法可以确保正确的滚动位置。。。最好的方法是通过缓存要在内存中显示的数据(在ViewModel中),确保始终在第一次布局传递之前在适配器上设置数据" . 这让我相信在ViewModel中有一种特殊的方法可以做到这一点。当然,我可以在ViewModel类中创建另一个变量,并在活动被销毁之前将滚动位置(
getBindingAdapterPosition()
)保存在那里,但这真的是我要问的最好的方法吗?@BenP。一旦检测到新数据,它就会调用notifyDataSetChanged()。我已经用adapter和viewmodel类更新了这个问题。