简体   繁体   English

使用 MVVM 视图模型和实时数据时,如何在配置更改后保留 RecyclerView 的滚动位置?

[英]How to preserve scroll position of a RecyclerView after a configuration change when using MVVM viewmodel and livedata?

READ FIRST: Apologies, it seems I have played myself.阅读第一:抱歉,看来我已经玩过自己了。 I was using RecyclerView in my xml earlier, but switched it over for CardStackView (it still uses the exact same RecyclerView adapter).我之前在我的 xml 中使用 RecyclerView,但将其切换为CardStackView (它仍然使用完全相同的 RecyclerView 适配器)。 If I switch back to RecyclerView, the original code below works - the scroll position is saved and restored automatically on configuration change.如果我切换回 RecyclerView,下面的原始代码有效 - 滚动位置会在配置更改时自动保存和恢复。

I'm using a MVVM viewmodel class which successfully retains list data for a RecyclerView after a configuration change.我正在使用 MVVM 视图模型类,该类在配置更改后成功保留了 RecyclerView 的列表数据。 However, the previous RecyclerView position is not restored.但是,之前的 RecyclerView 位置没有恢复。 Is this expected behaviour?这是预期的行为吗? What would be a good way to solve this?什么是解决这个问题的好方法?

I saw a blog post on medium briefly mentioning you can preserve scroll position by setting the adapter data before setting said adapter on the RecyclerView.在媒体上看到一篇博客文章,简要提到您可以通过在 RecyclerView 上设置所述适配器之前设置适配器数据来保留滚动位置。 From what I understand, after a configuration change the livedata that was being observed earlier gets a callback.据我了解,在配置更改后,之前观察到的实时数据会收到回调。 That callback is where I set my adapter data.该回调是我设置适配器数据的地方。 But it seems this callback happens after the onCreate() function finishes by which point my RecyclerView adapter is already set.但似乎这个回调是在 onCreate() 函数完成之后发生的,此时我的 RecyclerView 适配器已经设置好了。

class MainActivity : AppCompatActivity() {
    private val adapter = MovieAdapter()
    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Create or retrieve viewmodel and observe data needed for recyclerview
        viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
        viewModel.movies.observe(this, {
            adapter.items = it
        })

        binding.recyclerview.adapter = adapter

        // If viewmodel has no data for recyclerview, retrieve it
        if (viewModel.movies.value == null) viewModel.retrieveMovies()
    }
}
class MovieAdapter :
    RecyclerView.Adapter<MovieAdapter.MovieViewHolder>() {

    var items: List<Movie> by Delegates.observable(emptyList()) { _, _, _ ->
        notifyDataSetChanged()
    }

    class MovieViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val binding = ItemMovieCardBinding.bind(itemView)

        fun bind(item: Movie) {
            with(binding) {
                imagePoster.load(item.posterUrl)
                textRating.text = item.rating.toString()
                textDate.text = item.date
                textOverview.text = item.overview
            }
        }
    }


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_movie_card, parent, false)

        return MovieViewHolder(view)
    }

    override fun onBindViewHolder(holder: MovieViewHolder, position: Int) {
        holder.bind(items[position])
    }

    override fun getItemCount() = items.size
}
class MainViewModel : ViewModel() {
    private val _movies = MutableLiveData<List<Movie>>()
    val movies: LiveData<List<Movie>> get() = _movies

    fun retrieveMovies() {
        viewModelScope.launch {
            val client = ApiClient.create()
            val result: Movies = withContext(Dispatchers.IO) { client.getPopularMovies() }

            _movies.value = result.movies
        }
    }
}

Set adapter only after its items are available.只有在其项目可用后才设置适配器。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用 Room、ViewModel 和 LiveData 更改数据后重新加载 RecyclerView - Reload RecyclerView after data change with Room, ViewModel and LiveData MVVM:尝试使用 LiveData 加载数据时,ViewModel 为空 - MVVM: ViewModel is null when trying to load data using LiveData 如何在 MVVM 架构中观察 RecyclerView 适配器中的 LiveData? - How to observe LiveData in RecyclerView adapter in MVVM architecture? 将 RecyclerView 与 FirestoreRecyclerAdapter 一起使用时如何设置滚动位置? - How to set scroll position when using RecyclerView with FirestoreRecyclerAdapter? 使用 PagingDataAdapter 时如何恢复 recyclerview 滚动 position? - How to restore recyclerview scroll position when using PagingDataAdapter? 使用MVVM和LiveData时保存RecyclerView列表项更改的最佳实践? - Best practice to save changes of a RecyclerView list item when using MVVM and LiveData? 如何在使用Room Livedata MVVM时显示LoadingState - How to show LoadingState when using Room Livedata MVVM 是否可以在 RecyclerView 适配器或对话框中使用 MVVM ViewModel? - Is it possible using MVVM ViewModel in RecyclerView Adapter or Dialog? 如何使用Room和带有LiveData的ViewModel检索树结构,以便在包含子RecyclerViews的RecyclerView中使用? - How do you retrieve a tree structure using Room and a ViewModel with LiveData for use in RecyclerView containing sub-RecyclerViews? 如何使用 viewmodel 和 livedata 将数据从 recyclerview 传递到 android 中的片段 - How can i pass the data from recyclerview to fragment in android using viewmodel and livedata
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM