错误信息:
Fatal Exception: : Can not perform this action after onSaveInstanceState
at androidx.fragment.(:1844)
at (:1884)
at (:329)
at (:294)
at (:260)
背景:
在请求某业务Api时,网络请求失败,弹出DialogFragment,比如示例
val builder = () val tipDialog = (CommonConfirmDialog.TYPE_NO_CANCEL).setCancelOutSide(true) .setShowTitle(false).setBoldContent(true).setContent(errorMsg).build() (supportFragmentManager, "xxx_tip")
结果在 show的时候发生crash Fatal Exception: : Can not perform this action after onSaveInstanceState;
原因分析:
出现 IllegalStateException
是因为在 onSaveInstanceState
之后尝试执行 Fragment 事务。要解决这个问题,可以采用以下方法之一:出现 IllegalStateException
是因为在 onSaveInstanceState
之后尝试执行 Fragment 事务(如添加、移除或替换Fragment),这会导致状态丢失问题。
解决建议:
-
1. 使用
commitAllowingStateLoss()
这会允许状态丢失,但要谨慎使用,因为可能会导致意外问题。
-
2. 在
onSaveInstanceState
之前执行事务: 确保在onSaveInstanceState
方法调用之前完成所有Fragment事务。 -
3. 使用Handler或其他方式延迟事务: 使用Handler将事务推迟到
onSaveInstanceState
之后。
使用 commitAllowingStateLoss()
可能会导致一些意外问题:
-
1. 状态丢失:在某些情况下,如果应用程序在提交事务后被系统终止,可能会丢失一些状态或数据。这可能会导致不一致的 UI 状态。
-
2. 不一致的用户体验:由于状态可能丢失,用户可能会看到不一致的界面或操作,这可能会导致混淆或不良体验。
-
3. 调试困难:由于状态丢失的问题在调试过程中可能不容易发现,因此使用
commitAllowingStateLoss()
可能会使问题更难排查。
commitAllowingStateLoss()
应该作为最后的手段,只有在其他方法无法解决问题时才使用。
解决办法:
commitAllowingStateLoss()
val builder = ()
val tipDialog = (CommonConfirmDialog.TYPE_NO_CANCEL)
.setCancelOutSide(true)
.setShowTitle(false)
.setBoldContent(true)
.setContent(errorMsg)
.build()
(supportFragmentManager, "xxx_tip")
将 show
方法修改为以下形式:
().add(tipDialog, "xxx_tip
").commitAllowingStateLoss()
在 onSaveInstanceState
之前执行事务
确保事务在 onResume()
方法中完成,以确保它在 onSaveInstanceState()
之前执行,调用之前完成对话框的显示。例如,在 onResume
中执行:
override fun onResume() {
()
val builder = ()
val tipDialog = (CommonConfirmDialog.TYPE_NO_CANCEL)
.setCancelOutSide(true)
.setShowTitle(false)
.setBoldContent(true)
.setContent(errorMsg)
.build()
(supportFragmentManager, "xxx_tip
")
}
使用 Handler
延迟事务
val builder = ()
val tipDialog = (CommonConfirmDialog.TYPE_NO_CANCEL)
.setCancelOutSide(true)
.setShowTitle(false)
.setBoldContent(true)
.setContent(errorMsg)
.build()
val transaction = supportFragmentManager
val fragment: Fragment? = ("xxx_tip")
if (fragment != null) {
val fragmentTransaction: FragmentTransaction = () (fragment)
()
}
Handler(()).post {
(supportFragmentManager, "xxx_tip
")
}
commitNow()
-
commit()
: 事务是异步提交的,意味着它会被排队到主线程的消息队列中,可能会有一定的延迟。commitNow()
: 事务是同步提交的,意味着它会立即应用,确保事务的操作在代码继续执行之前完成。 -
commitNow 的好处:
-
立即应用
-
确定性: 使用
commitNow()
可以确保事务会立即生效。这在某些情况下很重要,比如当你需要在继续执行其他操作之前确保 Fragment 事务已经完成时。 -
避免 UI 问题
-
可见性: 如果你在进行一些依赖于 Fragment 的 UI 操作(例如更改 Fragment 的 UI 状态),
commitNow()
确保这些更改会立即可见,从而避免了因事务未完成而导致的 UI 问题。 -
减少潜在问题
-
状态管理: 在某些复杂的 Fragment 事务管理中,使用
commitNow()
可以帮助确保事务状态在继续执行其他代码之前是一致的,从而减少因事务未提交而导致的潜在问题。 -
总结: 根据实际情况选择合适的方法来确保Fragment事务在正确的生命周期内执行。