【问题标题】:Can a fragment's onAttach be called before the Activity's onCreate has finished?可以在 Activity 的 onCreate 完成之前调用 Fragment 的 onAttach 吗?
【发布时间】:2016-11-06 01:03:49
【问题描述】:

我正在尝试追查一次非常罕见的崩溃(数千次会话中的一次)。我有一个 Activity,在它的 onCreate 覆盖期间,它创建了一些片段,但没有显示或附加任何片段:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(R.layout.activity_main);

    mainMenuFragment = new MainMenuFragment();
    locationFragment = new LocationFragment();

    mainPresenter = new MainPresenter(this);
}

在这段代码中,我还创建了一个“MainPresenter”,它来自一个包含我们所有业务逻辑的库。 Presenter 是从 Fragments 的 onAttach 方法中使用的:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    MainActivity mainActivity = (MainActivity) activity;
    mainPresenter = mainActivity.getMainPresenter();
    mainPresenter.refreshUI();
}

问题是,我很少在 onAttach 中收到 null ptr 异常。在极少数情况下,片段的 onAttach 是否可能在活动的 onCreate 完成之前执行(即 mainPresenter 为空)?

更新

这是导致崩溃的调用堆栈的一部分,以防万一:

android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3253)
android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3349)
android.app.ActivityThread.handleRelaunchActivity (ActivityThread.java:5383)
android.app.ActivityThread.access$1200 (ActivityThread.java:221)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:1800)
android.os.Handler.dispatchMessage (Handler.java:102)
android.os.Looper.loop (Looper.java:158)
android.app.ActivityThread.main (ActivityThread.java:7225)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1230)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1120)

【问题讨论】:

  • 本周我遇到了这个确切的问题。我发现,如果我通过 Android Studio 的 Android Monitor 选项卡在后台终止应用程序后重新启动应用程序,这种情况会更常见。如果您需要可靠的复制品进行测试,这可能会很有用。
  • @stkent - 谢谢,我会试一试

标签: android android-fragments


【解决方案1】:

是的。请参阅https://developer.android.com/reference/android/app/Fragment.html#onCreate(android.os.Bundle) 的文档。 Fragment.onAttach 发生在 Fragment.onCreate 之前,如果 onCreate 的文档说活动在这个生命周期方法期间仍然可以处于创建过程中,那么这意味着它肯定可以在 onAttach 中构建,这发生在 onCreate 之前。

对于您的具体场景,如果这是您的整个 onCreate 活动,那么这些片段根本不会挂接到应用程序中;它们尚未通过片段管理器添加。它们只是实例化,还不能进行 Android 生命周期调用。我假设发生了一些更复杂的事情,并且在配置更改或发生崩溃时重新添加片段。

【讨论】:

  • 嗨,是的,这就是我的 onCreate 的全部内容,您已经找到了问题的重点 - 我已经看到您链接的文档,但重点是这些片段还没有已添加到片段管理器中,所以正如您所说,似乎正在发生更复杂的事情,我正在寻找可能是什么的答案。
  • 我已经用调用堆栈的一部分更新了这个问题,以防提供对奇怪问题的洞察力。
  • 由于 handleRelaunchActivity 位于该堆栈中,因此很可能在配置更改期间。在创建活动之前,在配置更改之前附加的片段正在重新附加到活动(由片段管理器)。您可以调用 getActivity() 并将其转换为 onActivityCreated() 中的 MainActivity。
  • 我认为您关于在 ActivityCreated 上进行 UI 更新的建议不会奏效 - 看起来好像 Activity 本身会不时重新创建。我想我需要将主演示者移动到一个静态实例中,这样它就不会被重新创建(业务逻辑不支持到处都有多个实例)
  • 为什么这不起作用?您对配置更改如何影响应用程序的熟悉程度如何?此外,我不会让演示者成为静态实例,因为您将活动作为对演示者的引用。那将是内存泄漏。您可以在活动的 onCreate 中检查 savedInstanceState 是否为空,以了解是否需要重新实例化这些片段,或者是否需要从片段管理器中获取它们。
【解决方案2】:

您可能希望将 Activity#onCreate 声明更改为:

@Override
protected void onCreate(Bundle savedInstanceState) {
    mainMenuFragment = new MainMenuFragment();

    locationFragment = new LocationFragment();

    mainPresenter = new MainPresenter(this);

    super.onCreate(savedInstanceState);

    requestWindowFeature(Window.FEATURE_NO_TITLE);

    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

   setContentView(R.layout.activity_main);
} 

这是因为 super.onCreate(savedInstanceState) 触发了活动片段的(重新)附加,并且系统通过调用 Fragment.onAttach() 来完成此操作。

但是,在您的情况下,mainPresenter 应该已经被实例化/初始化,因为它在 Fragment.onAttach 中是必需的,但现在还不是,因为它低于 super.onCreate(savedInstanceState)目前正在执行中。

【讨论】:

  • 自从我发布这个问题以来,我学到了很多关于活动和片段的知识。我认为您的回答是错误的,尽管我很感激。谷歌故意说要小心不要将片段生命周期与活动之一混淆。现实情况是,添加到片段管理器的片段可以在活动 onCreate 被调用之前创建和附加。
  • “现实情况是,添加到片段管理器中的片段可以在活动 onCreate 被调用之前创建和附加”.....我猜你只是在重复我的回答您自己的话,因为这正是我在回答中传递的内容。
  • 我猜你的答案基本上是以不太清晰的方式重新表述了早已被接受的答案。
猜你喜欢
  • 2017-03-24
  • 1970-01-01
  • 2015-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-15
  • 2017-08-20
相关资源
最近更新 更多