SupportFragmentManager 销毁,在幕后
SupportFragmentManager destroyed, behind the scenes
我的 MainActivity
:
上有这个场景
// onCreate
firebaseAuth.addAuthStateListener { firebaseAuth ->
when (firebaseAuth.currentUser) {
null -> {
hideAppBars()
clearBackStack(supportFragmentManager)
showFragment(fragment = LoginOrRegisterFragment())
}
else -> {
showAppBars()
clearBackStack(supportFragmentManager)
showFragment(fragment = HomeFragment())
}
}
}
clearBastack
只是一种弹出 Fragments 完整后台堆栈的方法:
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
和 resume 时按回键,我会得到 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.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
错误,因此您实际上应该只在 [=20] 时处理导航操作=] 至少开始了。
您可以使用 https://github.com/Zhuinden/live-event 作为例子。
我的 MainActivity
:
// onCreate
firebaseAuth.addAuthStateListener { firebaseAuth ->
when (firebaseAuth.currentUser) {
null -> {
hideAppBars()
clearBackStack(supportFragmentManager)
showFragment(fragment = LoginOrRegisterFragment())
}
else -> {
showAppBars()
clearBackStack(supportFragmentManager)
showFragment(fragment = HomeFragment())
}
}
}
clearBastack
只是一种弹出 Fragments 完整后台堆栈的方法:
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
和 resume 时按回键,我会得到 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.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
错误,因此您实际上应该只在 [=20] 时处理导航操作=] 至少开始了。
您可以使用 https://github.com/Zhuinden/live-event 作为例子。