片段转换的 ViewPager 和 RecyclerView 问题
ViewPager and RecyclerView issue with fragment transition
设置是这样的:
带有 nav_graph
的单个 activity 应用程序 (MainActivity)
HomeFragment 有带 3 个子片段的 viewPager2
这 3 个片段中的每一个都是相同的片段,RecyclerView 显示不同的 posts
列表
用户可以单击 post 并导航到全新的 screen/fragment(详细信息)
单击“后退”按钮引发异常:
java.lang.IllegalStateException: FragmentManager 已经在执行事务
在 androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:1790)
在 androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1826)
在 androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:297)
在 androidx.viewpager2.adapter.FragmentStateAdapter$FragmentMaxLifecycleEnforcer.updateFragme
所以我的感觉是问题发生在 ViewPager2 与 RecyclerView 和通过导航的 FragmentTransitions 之间。为什么?好吧,单击“后退”箭头会使事务转到 'home' 屏幕,但具有 viewpager 的主屏幕也会处理片段转换,这会以某种方式产生问题。
为了提供更多上下文,这是 tabs/viewpager 的设置方式(在 HomeFragment 中):
val viewPager: ViewPager2 = container.findViewById(R.id.viewPager)
viewPager.adapter = PagerAdapter(parentFragmentManager, lifecycle)
val tabLayout: TabLayout = container.findViewById(R.id.tabLayout)
val names = arrayOf("Najbolje", "Popularno", "Novo")
TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = names[position] }.attach()
这是适配器:
class PagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) {
private val fragments = listOf<Fragment>(
MyListFragment.newInstance(Type.TOP),
MyListFragment.newInstance(Type.POPULAR),
MyListFragment.newInstance(Type.NEW)
)
override fun getItemCount(): Int {
return fragments.size
}
override fun createFragment(position: Int): Fragment {
return fragments[position]
}
}
这里是设置 recyclerview 的代码:
private fun setupRecyclerView() {
val adapter = MyListAdapter(requireContext(), myService)
binding.recyclerView.adapter = adapter
binding.recyclerView.layoutManager = layoutManager
viewModel.posts.observe(viewLifecycleOwner) { post -> adapter.submitList(posts.map { PostItem(it) }) }
addScrollListener()
}
通过在 setTabs 方法中将 parentFragmentManager 更改为 childFragmentManager 在某处解决了一个类似的问题,但这会产生另一个问题,在 'RecyclerView already has layoutManager set up'
行中抛出异常
如果没有提供足够的信息,请告诉我。
到目前为止,通过尝试大量不同的类似实现,我无法在将“parentFragmentManager”更改为以下内容后重现该问题:activity?.supportFragmentManager
您使用了错误的 FragmentManager
- 每个 完全包含在另一个布局中的片段(例如您的 ViewPager2
托管片段),您必须使用childFragmentManager
正确嵌套片段。
viewPager.adapter = PagerAdapter(childFragmentManager, lifecycle)
这不仅是为了正确恢复您的状态(使用 activity 的 supportFragmentManager
做不到的事情),而且为了确保父片段首先经历其状态转换是必需的只有这样,子片段才会通过它们的转换,解决“已经执行的事务”问题。
设置是这样的:
带有 nav_graph
的单个 activity 应用程序 (MainActivity)HomeFragment 有带 3 个子片段的 viewPager2
这 3 个片段中的每一个都是相同的片段,RecyclerView 显示不同的 posts
列表用户可以单击 post 并导航到全新的 screen/fragment(详细信息)
单击“后退”按钮引发异常:
java.lang.IllegalStateException: FragmentManager 已经在执行事务 在 androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:1790) 在 androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1826) 在 androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord.java:297) 在 androidx.viewpager2.adapter.FragmentStateAdapter$FragmentMaxLifecycleEnforcer.updateFragme
所以我的感觉是问题发生在 ViewPager2 与 RecyclerView 和通过导航的 FragmentTransitions 之间。为什么?好吧,单击“后退”箭头会使事务转到 'home' 屏幕,但具有 viewpager 的主屏幕也会处理片段转换,这会以某种方式产生问题。
为了提供更多上下文,这是 tabs/viewpager 的设置方式(在 HomeFragment 中):
val viewPager: ViewPager2 = container.findViewById(R.id.viewPager)
viewPager.adapter = PagerAdapter(parentFragmentManager, lifecycle)
val tabLayout: TabLayout = container.findViewById(R.id.tabLayout)
val names = arrayOf("Najbolje", "Popularno", "Novo")
TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = names[position] }.attach()
这是适配器:
class PagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) {
private val fragments = listOf<Fragment>(
MyListFragment.newInstance(Type.TOP),
MyListFragment.newInstance(Type.POPULAR),
MyListFragment.newInstance(Type.NEW)
)
override fun getItemCount(): Int {
return fragments.size
}
override fun createFragment(position: Int): Fragment {
return fragments[position]
}
}
这里是设置 recyclerview 的代码:
private fun setupRecyclerView() {
val adapter = MyListAdapter(requireContext(), myService)
binding.recyclerView.adapter = adapter
binding.recyclerView.layoutManager = layoutManager
viewModel.posts.observe(viewLifecycleOwner) { post -> adapter.submitList(posts.map { PostItem(it) }) }
addScrollListener()
}
通过在 setTabs 方法中将 parentFragmentManager 更改为 childFragmentManager 在某处解决了一个类似的问题,但这会产生另一个问题,在 'RecyclerView already has layoutManager set up'
行中抛出异常如果没有提供足够的信息,请告诉我。
到目前为止,通过尝试大量不同的类似实现,我无法在将“parentFragmentManager”更改为以下内容后重现该问题:activity?.supportFragmentManager
您使用了错误的 FragmentManager
- 每个 完全包含在另一个布局中的片段(例如您的 ViewPager2
托管片段),您必须使用childFragmentManager
正确嵌套片段。
viewPager.adapter = PagerAdapter(childFragmentManager, lifecycle)
这不仅是为了正确恢复您的状态(使用 activity 的 supportFragmentManager
做不到的事情),而且为了确保父片段首先经历其状态转换是必需的只有这样,子片段才会通过它们的转换,解决“已经执行的事务”问题。