我正在使用新的ConcatAdapter和 Android 导航组件来创建一个复杂的 recyclerView,其中包含嵌套的水平滚动列表。我正在尝试恢复这些嵌套列表在旋转、导航等方面的状态。我已经阅读了关于该主题的这篇文章,但我正在努力解决如何在这种情况下恢复状态。
当adapter.stateRestorationPolicy = PREVENT_WHEN_EMPTY
我将它应用于包含嵌套回收器视图的适配器时,上面的文章中的内容不起作用。我在收到数据时尝试更新嵌套适配器,并尝试在数据接收时将它们添加到 concat 适配器,但没有成功。
我的片段
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val concatAdapter = ConcatAdapter()
binding.recyclerView.apply {
adapter = concatAdapter
layoutManager = LinearLayoutManager(requireContext())
}
viewModel.data.observe(viewLifecycleOwner, { listItems ->
concatAdapter.addAdapter(NestedListAdapter(listItems))
})
}
也试过这个:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val nestedListAdapter = NestedListAdapter()
val concatAdapter = ConcatAdapter(nestedListAdapter)
binding.recyclerView.apply {
adapter = concatAdapter
layoutManager = LinearLayoutManager(requireContext())
}
viewModel.movies.observe(viewLifecycleOwner, { items ->
nestedListAdapter.clearItems()
nestedListAdapter.addItems(items)
nestedListAdapter.notifyItemRangeChanged(0, items.size)
})
}
我还尝试延迟将适配器绑定到外部 recyclerview:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
lateinit var concatAdapter: ConcatAdapter()
binding.recyclerView.apply {
layoutManager = LinearLayoutManager(requireContext())
}
viewModel.movies.observe(viewLifecycleOwner, { items ->
concatAdapter = ConcatAdapter(MovieHorizontalListAdapter(it.data.toMutableList()))
if (binding.recyclerView.adapter != concatAdapter) {
binding.recyclerView.adapter = concatAdapter
}
})
}
我的嵌套 Recyclerview 适配器
class NestedListAdapter(
private val listItems: MutableList<Movie> = mutableListOf()
) : RecyclerView.Adapter<NestedListAdapter.ViewHolder>() {
private val scrollStates: MutableMap<String, Parcelable?> = mutableMapOf()
private val viewPool = RecyclerView.RecycledViewPool()
init {
// this does not do anything, (it's also added in the MovieListAdapter)
stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY
}
private fun getSectionID(position: Int): String {
return listItems.getOrNull(position)?.id?.toString().orEmpty()
}
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
val key = getSectionID(holder.layoutPosition)
scrollStates[key] = holder.rv.layoutManager?.onSaveInstanceState()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = NestedListAdapterBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return ViewHolder(binding)
}
override fun getItemCount(): Int = if (listItems.isEmpty()) 0 else 1
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(listItems)
}
inner class ViewHolder(
binding: NestedListAdapterBinding
) : RecyclerView.ViewHolder(binding.root) {
val rv = binding.recyclerView
fun bind(listItems: List<Movie>) {
val lm = LinearLayoutManager(rv.context, HORIZONTAL, false)
lm.initialPrefetchItemCount = 4
rv.apply {
setRecycledViewPool(viewPool)
layoutManager = lm
adapter = MovieListAdapter(listItems)
}
restoreState()
}
// This is to restore the state when recycling items (not rotation)
private fun restoreState() {
val key = getSectionID(layoutPosition)
val state = scrollStates[key]
if (state != null) {
rv.layoutManager?.onRestoreInstanceState(state)
} else {
val padding = rv.resources.getDimension(R.dimen.default_padding).toInt()
rv.addItemDecoration(HorizontalListMarginDecoration(padding))
rv.layoutManager?.scrollToPosition(0)
}
}
}
任何帮助表示赞赏。