FragmentStateAdapter 崩溃,抛出 java.lang.IllegalStateException
FragmentStateAdapter crashes, throwing java.lang.IllegalStateException
在我的应用程序中,我有一个带有按钮的 PlaylistMenuFragment
,该按钮通过以下方法将 ViewPager
中的自身替换为 PlaylistContentFragment
,反之亦然:
fun goToPlaylistContent() {
pagerAdapter.replaceLastFragmentWith(PlaylistContentFragment())
}
fun goToPlaylistMenu() {
pagerAdapter.replaceLastFragmentWith(PlaylistMenuFragment())
}
正在调用的适配器方法:
fun replaceLastFragmentWith(newFragment: Fragment) {
fragmentList[LAST_FRAGMENT_INDEX] = newFragment
notifyItemChanged(LAST_FRAGMENT_INDEX)
}
如果我单击 PlaylistMenuFragment
中的一个按钮转到 PlaylistContentFragment
,执行上述方法,一切正常。但是,如果我点击 PlaylistContentFragment
中的一个按钮返回到 PlaylistMenuFragment
,应用程序崩溃,抛出以下异常:
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling androidx.viewpager2.widget.ViewPager2$RecyclerViewImpl{8ebfd7a VFED..... ......ID 0,0-720,1040 #1}, adapter:com.pegoraro.musicast.main.PagerAdapter@a12492b, layout:androidx.viewpager2.widget.ViewPager2$LinearLayoutManagerImpl@e567188, context:com.pegoraro.musicast.main.MainActivity@e8e6424
崩溃追溯到上面的方法。如果我用 try-catch 块将 notifyItemChanged 包装在适配器方法中,应用程序将按预期工作,没有任何问题迹象,除非我查看 logcat,它仍然显示抛出的异常。这是一个肮脏的修复,我不喜欢它:
fun replaceLastFragmentWith(newFragment: Fragment) {
fragmentList[LAST_FRAGMENT_INDEX] = newFragment
try {
notifyItemChanged(LAST_FRAGMENT_INDEX)
} catch (e: Exception) {
Log.d("TEST", e.toString())
}
}
我正在尝试在 TabLayout
中的这两个片段之间实现一种导航,这就是我设法做到的方式。因此,如果错误来自我如何处理此问题的基本问题,那么有什么替代方法?如果不是,问题的原因可能是什么?谢谢。
在 ViewPager2
适配器上调用任何 notifyXX()
方法与 RecyclerView
相同,因为 ViewPager2
内部功能基于 RecyclerView。
并且由于 notifyXX()
方法在后台线程中工作,在您的情况下,这会直接影响 ViewPager 当前片段之一;所以你需要在 UI thread
中明确地执行此操作
viewpager.post {
notifyItemChanged(LAST_FRAGMENT_INDEX)
}
在我的应用程序中,我有一个带有按钮的 PlaylistMenuFragment
,该按钮通过以下方法将 ViewPager
中的自身替换为 PlaylistContentFragment
,反之亦然:
fun goToPlaylistContent() {
pagerAdapter.replaceLastFragmentWith(PlaylistContentFragment())
}
fun goToPlaylistMenu() {
pagerAdapter.replaceLastFragmentWith(PlaylistMenuFragment())
}
正在调用的适配器方法:
fun replaceLastFragmentWith(newFragment: Fragment) {
fragmentList[LAST_FRAGMENT_INDEX] = newFragment
notifyItemChanged(LAST_FRAGMENT_INDEX)
}
如果我单击 PlaylistMenuFragment
中的一个按钮转到 PlaylistContentFragment
,执行上述方法,一切正常。但是,如果我点击 PlaylistContentFragment
中的一个按钮返回到 PlaylistMenuFragment
,应用程序崩溃,抛出以下异常:
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling androidx.viewpager2.widget.ViewPager2$RecyclerViewImpl{8ebfd7a VFED..... ......ID 0,0-720,1040 #1}, adapter:com.pegoraro.musicast.main.PagerAdapter@a12492b, layout:androidx.viewpager2.widget.ViewPager2$LinearLayoutManagerImpl@e567188, context:com.pegoraro.musicast.main.MainActivity@e8e6424
崩溃追溯到上面的方法。如果我用 try-catch 块将 notifyItemChanged 包装在适配器方法中,应用程序将按预期工作,没有任何问题迹象,除非我查看 logcat,它仍然显示抛出的异常。这是一个肮脏的修复,我不喜欢它:
fun replaceLastFragmentWith(newFragment: Fragment) {
fragmentList[LAST_FRAGMENT_INDEX] = newFragment
try {
notifyItemChanged(LAST_FRAGMENT_INDEX)
} catch (e: Exception) {
Log.d("TEST", e.toString())
}
}
我正在尝试在 TabLayout
中的这两个片段之间实现一种导航,这就是我设法做到的方式。因此,如果错误来自我如何处理此问题的基本问题,那么有什么替代方法?如果不是,问题的原因可能是什么?谢谢。
在 ViewPager2
适配器上调用任何 notifyXX()
方法与 RecyclerView
相同,因为 ViewPager2
内部功能基于 RecyclerView。
并且由于 notifyXX()
方法在后台线程中工作,在您的情况下,这会直接影响 ViewPager 当前片段之一;所以你需要在 UI thread
viewpager.post {
notifyItemChanged(LAST_FRAGMENT_INDEX)
}