【问题标题】:FragmentManager NullPointerException when trying to commitAllowingStateLoss尝试 commitAllowingStateLoss 时出现 FragmentManager NullPointerException
【发布时间】:2023-03-31 18:45:01
【问题描述】:

上下文:我有一个Activity,一个Fragment 和3 个InnerFragments。当调用FragmentonDestroy() 时,我想从FragmentManager 中删除内部片段。来自onDestroy() 的代码如下。

问题: FragmentManager 抛出 NullPointerException,可能是在调用 commitAllowingStateLoss() 时。我不明白为什么。

@Override
public void onDestroy()
{
    super.onDestroy();
    if (getFragmentManager().findFragmentById(R.id.fragment_framelayout_left) != null)
    {
        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        fragmentTransaction.remove(mLeftFragment);
        fragmentTransaction.commitAllowingStateLoss();
    }
}

堆栈跟踪:

02-11 12:15:14.162: E/AndroidRuntime(25911): FATAL EXCEPTION: main
02-11 12:15:14.162: E/AndroidRuntime(25911): java.lang.NullPointerException
02-11 12:15:14.162: E/AndroidRuntime(25911):    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1419)
02-11 12:15:14.162: E/AndroidRuntime(25911):    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429)
02-11 12:15:14.162: E/AndroidRuntime(25911):    at android.os.Handler.handleCallback(Handler.java:725)
02-11 12:15:14.162: E/AndroidRuntime(25911):    at android.os.Handler.dispatchMessage(Handler.java:92)
02-11 12:15:14.162: E/AndroidRuntime(25911):    at android.os.Looper.loop(Looper.java:137)
02-11 12:15:14.162: E/AndroidRuntime(25911):    at android.app.ActivityThread.main(ActivityThread.java:5039)
02-11 12:15:14.162: E/AndroidRuntime(25911):    at java.lang.reflect.Method.invokeNative(Native Method)
02-11 12:15:14.162: E/AndroidRuntime(25911):    at java.lang.reflect.Method.invoke(Method.java:511)
02-11 12:15:14.162: E/AndroidRuntime(25911):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
02-11 12:15:14.162: E/AndroidRuntime(25911):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
02-11 12:15:14.162: E/AndroidRuntime(25911):    at dalvik.system.NativeStart.main(Native Method)

【问题讨论】:

  • 我没有完全遵循您的架构。 InnerFragments 住在Fragment 中吗?如果是这样,我认为您应该让getChildFragmentManager() 管理它们(而不是ActivityFragmentManager)。这样,当 Fragment 销毁时,它的子 InnerFragments 也会销毁,而无需此额外代码。
  • 是的,内部碎片存在于碎片内部(至少在平板电脑上)。在手机上,它们存在于一个 Activity 中(InnerFragment1 在 Activity1 中,InnerFragment2 在 Activity2 中)。这就是我使用该代码的原因。它也可以与活动中的 getChildFragmentManager() 一起使用吗? LE:愚蠢的问题,对不起。我会在几个小时内尝试你的想法,看看效果如何。
  • getChildFragmentManager() 仅在Fragments 中,因为Activities 无法访问儿童FragmentManagers。但是,Fragments 可以调用 getFragmentManager() 并访问其父 ActivityFragmentManager,允许他们在自己之上开始新的 Fragments,而无需其父 Activity 为他们做这件事。跨度>
  • 你能提供你为此重写的代码吗?我有同样的问题,但我没有按照 Steven 的建议来解决这个问题。

标签: android android-fragments android-fragmentactivity


【解决方案1】:

FragmentManagerActivity 级别管理所有Fragments,它们的生命周期将与父Activity 绑定。子Fragment 经理在Fragment 级别管理所有Fragments,它们的生命周期将与该父Fragment 绑定。

因此,对于您的手机架构,请使用getFragmentManager() 将您的InnerFragment 添加到您的Activity。当Activity 永久销毁时(通过后退按钮/finish()),FragmentManager 将为您销毁并释放InnerFragment

对于您的平板电脑架构,使用getChildFragmentManager()(在最新的支持库中)将您的InnerFragments 添加到您的Fragment。当Fragment 永久销毁时,FragmentManager 将为您销毁并释放InnerFragments

您不必自己管理释放和销毁您的Fragments。我建议记录您的 ActivitiesFragments 的生命周期事件,以便您可以观察它们的状态并确保正确的行为。

【讨论】:

  • 太棒了。非常感谢。这解决了它。一个小问题。如果我使用 ChildFragmentManager,我无法在子片段上设置 RetainInstance(true)。有解决方法吗?或者为什么它应该这样?
  • 使用setRetainInstance(true) 实际上已经是一种解决方法。 Google 建议的方法是将任何变量状态保存在 onSaveInstanceState() 中并在 onCreateonCreateView 中恢复它。在任何时候,操作系统可能内存不足并需要销毁您的Fragments 和/或Activities,因此他们有责任保存它们当前的状态,并恢复该状态以显示给用户因为他们回来时什么都没有改变。以下是 Google 建议您保存状态 developer.android.com/training/basics/activity-lifecycle/… 的方式。
  • 这里有更多关于setRetainInstance(true) - stackoverflow.com/questions/11182180/…的信息
  • 是的,我知道如何为活动保存状态。对于片段,我总是使用 setRetainInstance。但我会调查一下。非常感谢队友!你已经提供了更多的帮助!
  • 啊,很好,Fragments 的保存状态与Activitys 非常相似。要记住的技巧是在savedInstanceState != null 时恢复onCreate(不是onCreateView)中的变量,然后在onCreateView 中设置您的视图并将这些恢复的值设置为它们。如果你有你的Fragments 在一个后栈中,当你回击返回它们时,onCreateView 被调用,但onCreate 没有。因此,如果您尝试在onCreateView 中恢复/默认变量(就像我第一次做的那样),事情就会变得一团糟。希望这会有所帮助。
【解决方案2】:

NullPointerException 是由于 Activity 的 Handler 未从 FragmentManager 设置的事实引起的,因此防止崩溃的“解决方案”如下:

public void onDestroy(){
        super.onDestroy();
        try {
            Field mActivityField = getFragmentManager().getClass().getDeclaredField("mActivity");
            mActivityField.setAccessible(true);
            mActivityField.set(getFragmentManager(), this);

            Field mPendingActionsField = getFragmentManager().getClass().getDeclaredField("mPendingActions");
            mPendingActionsField.setAccessible(true);
            mPendingActionsField.set(getFragmentManager(), null);


            Field f = Activity.class.getDeclaredField("mHandler");
            f.setAccessible(true);
            Handler handler = (Handler) f.get(this);
            handler.close();
        } catch (Throwable e) {

        }
}

【讨论】:

    【解决方案3】:

    CASE:当你需要从另一个Fragment(Parent Fragment)调用Fragment(Child Fragment)时

    在父片段中始终使用getChildFragmentManager() 而不是getFragmentManager

    Read documentation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-13
      • 2010-12-11
      • 1970-01-01
      • 1970-01-01
      • 2017-07-22
      • 2016-09-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多