【问题标题】:When to use FragmentManager.isDestroyed()? To avoid IllegalStateException?何时使用 FragmentManager.isDestroyed()?避免 IllegalStateException?
【发布时间】:2015-09-28 01:07:01
【问题描述】:

在另一个线程上完成网络请求后,我的 Activity 中有一个侦听器替换 Fragment。所以这个监听器正在调用这样一行代码:

getFragmentManager().beginTransaction().replace(R.id.container, fragment, fragmentTag).commit();

这行代码中的 commit() 偶尔会抛出 IllegalStateException。根据the docs

事务只能在其包含的活动保存其状态之前使用此方法提交。如果在该点之后尝试提交,则会引发异常。这是因为如果活动需要从其状态恢复,则提交后的状态可能会丢失。请参阅 commitAllowingStateLoss() 以了解可能会丢失提交的情况。

在研究这个问题时,我遇到了FragmentManager.isDestroyed() 方法。 javadocs 阅读:

如果对 FragmentManager 的 Activity 进行了最终的 Activity.onDestroy() 调用,则返回 true,因此该实例现在已死。

我想我只是对 FragmentManager 的 Activity 实例死亡的含义有点困惑。我们什么时候应该使用 FragmentManager.isDestroyed()?在提交替换 FragmentTransaction 之前检查它会避免 IllegalStateException 吗?

【问题讨论】:

  • 你应该发布你的 logcat 错误
  • 我一直在经历同样的事情......我发现这是完全正确的:在我所有 FragmentManager.isDestroyed() 返回 true 的情况下,FragmentTransaction.commit() 将抛出 IllegalStateException .实际上,首先检查 .isDestroyed() 将帮助您避免异常,但您也不会执行 Fragment 事务。
  • @alpartis 我将添加一些更好的日志记录,看看当我收到 IllegalStateException 时 FragmentManager.isDestroyed() 是否返回 true。不过,您的评论似乎足以成为答案。如果您将它作为一个发布,并且在一段时间内没有人发布更好的,我会接受它。

标签: android fragmentmanager


【解决方案1】:

我的代码如下所示。执行时,要么工作,要么显示我想要的片段,或者我收到指示 .isDestroyed() 为真的日志消息。如果我取消对 .isDestroyed() 的检查,那么 ft.commit() 将抛出 IllegalStateException。

此解决方案可防止由此导致的崩溃,但不一定能解决导致崩溃的根本时间问题。

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragementTransaction;

public class CallingCard extends Fragment
{
    // ... some stuff for my fragment ...
}

public class MyFragment extends Fragment
{
    public void showCallingCard() {
        CallingCard callingCard = new CallingCard();
        FragmentManager fm = parent.getSupportFragmentManager();

        // ensure serialization of fragment transactions
        fm.executePendingTransactions();

        if (!fm.isDestroyed()) {
            // attempt to display fragment
            FragementTransaction ft = fm.beginTransaction();
            ft.replace(R.id.fragPlaceHolder, callingCard);
            ft.commit();
        } else {
            Log.e("tag", "fm.isDestroyed() was true");
        }
    }
}

【讨论】:

  • 在我的情况下,片段之前的使用没有被正确/完全清理,但他们的.Destroy()等方法已经被调用。随后,当我的片段第二次出现时,内部状态变量完全不正常(这是一个技术术语),我的片段事务将失败,因为 Android 仍然认为包含的片段仍然被破坏(如 @ 的结果所示987654324@).
  • 开始从我的日志中取回一些数据,但我仍然遇到崩溃,看起来fm.isDestroyed() 正在返回false
  • Android 不一定在所有情况下都按照您的想法准确处理片段事务。在某些情况下,您需要一些蛮力来确保正确的序列化。在开始新事务之前添加对.executePendingTransactions() 的调用。我会尝试更新我上面的答案以反映这一点。
  • .executePendingTransactions() 返回 false,这意味着没有任何待执行的事务要执行。
【解决方案2】:

维护一个标志以了解 Activity 的当前状态。检查 onPause 状态。

在活动进入 onPause 状态后不要进行片段管理器事务。这对我有用..!!!

@Override
protected void onPause() {
    super.onPause();
    isPaused = true;

}

@Override
protected void onResume() {
    super.onResume();
    isPaused = false;
}

// 检查 isPaused 标志。

if (!isPaused) {
        fragmentManager.popBackStack(fragment.getClass().getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
        fragmentManager.beginTransaction()
                // .setCustomAnimations(android.R.anim.fade_in,android.R.anim.fade_out)
                .replace(R.id.container, fragment)
                .commitAllowingStateLoss();
    }

【讨论】:

    猜你喜欢
    • 2020-03-29
    • 1970-01-01
    • 2015-02-18
    • 2013-12-28
    • 1970-01-01
    • 2016-02-10
    • 2021-01-02
    • 2016-03-24
    • 2012-07-04
    相关资源
    最近更新 更多