问题描述
我的MainActivity
上有这种情况:
// onCreate
firebaseAuth.addAuthStateListener { firebaseAuth ->
when (firebaseAuth.currentUser) {
null -> {
hideAppBars()
clearBackStack(supportFragmentManager)
showFragment(fragment = LoginorRegisterFragment())
}
else -> {
showAppBars()
clearBackStack(supportFragmentManager)
showFragment(fragment = HomeFragment())
}
}
}
clearBastack
只是从片段的整个后栈弹出的一种方法:
private fun clearBackStack(fragmentManager: FragmentManager) {
with(fragmentManager) {
if (backStackEntryCount > 0)
popBackStack()
}
}
和showFragment
方法:
fun showFragment(fragment: Fragment,addToBackStack: Boolean = false) {
supportFragmentManager.beginTransaction().apply {
replace(R.id.fragmentContainer,fragment)
if (addToBackStack) addToBackStack(null)
}.commit()
}
在通常的流程中,一切正常。点击登录:BackStack清除,从LoginFragment
进入HomeFragment
。但是,如果我进入LoginFragment
后按回去并继续,则会得到IllegalStateException: FragmentManager has been destroyed
似乎可以解决此问题的
明确检查if(!supportFragmentManager.isDestroyed)
:
fun showFragment(fragment: Fragment,addToBackStack: Boolean = false) {
if (!supportFragmentManager.isDestroyed) {
supportFragmentManager.beginTransaction().apply {
replace(R.id.fragmentContainer,fragment)
if (addToBackStack) addToBackStack(null)
}.commit()
}
}
更新:完整堆栈跟踪:
java.lang.IllegalStateException: FragmentManager has been destroyed
at androidx.fragment.app.FragmentManager.enqueueAction(FragmentManager.java:1725)
at androidx.fragment.app.BackStackRecord.commitInternal(BackStackRecord.java:321)
at androidx.fragment.app.BackStackRecord.commit(BackStackRecord.java:286)
at com.coroutinedispatcher.datacrypt.MainActivity.showFragment(MainActivity.kt:57)
at com.coroutinedispatcher.datacrypt.MainActivity.showFragment$default(MainActivity.kt:52)
at com.coroutinedispatcher.datacrypt.MainActivity$onCreate$1.onAuthStateChanged(MainActivity.kt:36)
at com.google.firebase.auth.zzj.run(com.google.firebase:firebase-auth@@19.4.0:3)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at com.google.android.gms.internal.firebase_auth.zzj.dispatchMessage(com.google.firebase:firebase-auth@@19.4.0:6)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
引发的行是supportFragmentManager.apply{bla()}.commit()
。
问题是,为什么,后台实际上发生了什么?
解决方法
您应在Activity的onDestroy中删除AuthStateListnener。
// onCreate
private val authStateListener = AuthStateListener { firebaseAuth ->
when (firebaseAuth.currentUser) {
null -> {
hideAppBars()
clearBackStack(supportFragmentManager)
showFragment(fragment = LoginOrRegisterFragment())
}
else -> {
showAppBars()
clearBackStack(supportFragmentManager)
showFragment(fragment = HomeFragment())
}
}
}
override fun onCreate(...) {
super.onCreate(...)
firebaseAuth.addAuthStateListener(authStateListener)
}
override fun onDestroy() {
firebaseAuth.removeAuthStateListener(authStateListener)
super.onDestroy()
}
尽管从技术上讲,您还应该考虑到这仍可能在onStop
之后触发片段事务,这将导致this action cannot be performed after onSaveInstanceState
错误,因此实际上您应该仅在Activity至少已启动时才处理导航操作