fix: Sentry-418688 SearchActivity回调onSavedInstance后,调用FragmentManager的popBackStack引发的崩溃问题

This commit is contained in:
曾祥俊
2024-11-07 13:42:39 +08:00
parent ab66621751
commit cf527db60e
2 changed files with 76 additions and 1 deletions

View File

@ -0,0 +1,74 @@
package com.gh.common.fragment
import androidx.fragment.app.FragmentManager
import java.lang.reflect.Field
fun FragmentManager.popBackStackAllowStateLoss() {
popBackStackAllowStateLoss(-1, 0)
}
fun FragmentManager.popBackStackAllowStateLoss(id: Int, flags: Int) {
if (!isStateSaved) {
popBackStack(id, flags)
} else {
hook { popBackStack(id, flags) }
}
}
fun FragmentManager.popBackStackAllowStateLoss(name: String?, flags: Int) {
if (!isStateSaved) {
popBackStack(name, flags)
} else {
hook { popBackStack(name, flags) }
}
}
fun FragmentManager.popBackStackImmediateAllowStateLoss() = popBackStackAllowStateLoss(-1, 0)
fun FragmentManager.popBackStackImmediateAllowStateLoss(id: Int, flags: Int) =
if (!isStateSaved) {
popBackStackImmediate(id, flags)
} else {
hook { popBackStackImmediate(id, flags) }
}
fun FragmentManager.popBackStackImmediateAllowStateLoss(name: String?, flags: Int): Boolean =
if (!isStateSaved) {
popBackStackImmediate(name, flags)
} else {
hook { popBackStackImmediate(name, flags) }
}
/**
* 通过反射将FragmentManager的mStateSaved和mStopped设为false否则Activity在回调onSavedInstance以后
* 调用Fragment的popBackStack和popBackStackImmediate方法会触发“java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState”的异常。
* @see <a href="https://sentry.shanqu.cc/organizations/lightgame/issues/418688/?project=22">Sentry-418688</a>
*/
private fun <T> FragmentManager.hook(callback: FragmentManager.() -> T): T {
val mStateSavedField = getField(this::class.java,"mStateSaved")
val stateSaved = mStateSavedField.get(this);
mStateSavedField.set(this, false)
val mStoppedField = getField(this::class.java,"mStopped")
val stopped = mStateSavedField.get(this);
mStoppedField.set(this, false)
val result = callback.invoke(this)
mStateSavedField.set(this, stateSaved)
mStoppedField.set(this, stopped)
return result
}
@Throws(NoSuchFieldException::class)
private fun getField(clazz: Class<*>, name: String): Field {
var cls: Class<*>? = clazz
while (cls != null) {
try {
val declaredField = cls.getDeclaredField(name)
declaredField.isAccessible = true
return declaredField
} catch (e: NoSuchFieldException) {
e.printStackTrace()
}
cls = cls.superclass
}
throw NoSuchFieldException()
}

View File

@ -15,6 +15,7 @@ import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import com.gh.common.fragment.popBackStackAllowStateLoss
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.LogUtils
import com.gh.gamecenter.DisplayType.*
@ -381,7 +382,7 @@ open class SearchActivity : BaseActivity() {
}
protected fun popBackToFragment(tag: String) {
supportFragmentManager.popBackStack(tag, 0)
supportFragmentManager.popBackStackAllowStateLoss(tag, 0)
}
@Subscribe(threadMode = ThreadMode.MAIN)