: Can not perform this action after onSaveInstanceState

时间:2024-10-22 16:08:42

 错误信息:

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. 1. 使用commitAllowingStateLoss()

    这会允许状态丢失,但要谨慎使用,因为可能会导致意外问题。

  2. 2. 在onSaveInstanceState之前执行事务: 确保在onSaveInstanceState方法调用之前完成所有Fragment事务。

  3. 3. 使用Handler或其他方式延迟事务: 使用Handler将事务推迟到onSaveInstanceState之后。

使用 commitAllowingStateLoss() 可能会导致一些意外问题:
  1. 1. 状态丢失:在某些情况下,如果应用程序在提交事务后被系统终止,可能会丢失一些状态或数据。这可能会导致不一致的 UI 状态。

  2. 2. 不一致的用户体验:由于状态可能丢失,用户可能会看到不一致的界面或操作,这可能会导致混淆或不良体验。

  3. 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()
  1. commit(): 事务是异步提交的,意味着它会被排队到主线程的消息队列中,可能会有一定的延迟。

    commitNow(): 事务是同步提交的,意味着它会立即应用,确保事务的操作在代码继续执行之前完成。

  2. commitNow 的好处:

  3. 立即应用

  4.         确定性: 使用 commitNow() 可以确保事务会立即生效。这在某些情况下很重要,比如当你需要在继续执行其他操作之前确保 Fragment 事务已经完成时。

  5. 避免 UI 问题

  6.         可见性: 如果你在进行一些依赖于 Fragment 的 UI 操作(例如更改 Fragment 的 UI 状态),commitNow() 确保这些更改会立即可见,从而避免了因事务未完成而导致的 UI 问题。

  7. 减少潜在问题

  8.         状态管理: 在某些复杂的 Fragment 事务管理中,使用 commitNow() 可以帮助确保事务状态在继续执行其他代码之前是一致的,从而减少因事务未提交而导致的潜在问题。

  9. 总结: 根据实际情况选择合适的方法来确保Fragment事务在正确的生命周期内执行。