简体   繁体   English

为什么 Fragment 的 onCreate() 有时会先于 Activity 的 onCreate() 被调用?

[英]Why Fragment's onCreate() is sometimes called prior to Activity's onCreate()?

Recently I came across a hard to reproduce issue.最近我遇到了一个难以重现的问题。 The NPE occurs when a fragment tries to initialize ArrayAdapter with the data from Activity.当片段尝试使用来自 Activity 的数据初始化 ArrayAdapter 时,会发生 NPE。 The default list initialized in Activity's onCreate method:在 Activity 的 onCreate 方法中初始化的默认列表:

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...
    mAccounts = new ArrayList<>();
    // ...
}

@Override
public List<Account> getAccounts(){
    return mAccounts;
}

The fragment creates a list adapter also in its onCreate() :该片段还在其onCreate()中创建了一个列表适配器:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
    setHasOptionsMenu(true);

    //mAccountProvider is an interface implemented by the activity
    mAccounts = mAccountProvider.getAccounts();

    mAccountAdapter = new AccountAdapter(getActivity(), R.layout.account_list_item, mAccounts);
}

The NPE occurs inside the AccountAdapter when default getCount() method is called.当调用默认的getCount()方法时,NPE 发生在AccountAdapter内部。 The reason is that mAccounts is null. The issue appears seldom and I wasn't able to reproduce it.原因是mAccounts是 null。这个问题很少出现,我无法重现。

When is it possible that fragment's onCreate() is called before activity's onCreate() ?什么时候可以在活动的onCreate()之前调用片段的onCreate () ? According to the source code, Fragment's onCreate() is dispatched in the Activity's onCreate() .根据源代码,Fragment 的onCreate()是在 Activity 的onCreate( ) 中调度的。 Why is is it then called after Activity's onCreate() has finished its execution?为什么在 Activity 的 onCreate() 执行完成后调用它?

The Activities callback isn't called after the Fragments; 碎片后不调用活动回调; the Fragment's is called during the Activity's. 片段是在活动期间调用的。

Initialise mAccounts before calling super.onCreate() in Activity.onCreate() Activity.onCreate()调用super.onCreate()之前初始化mAccounts

onCreate() of your fragment can be called before onCreate() method of your activity has been finished. onCreate()的片段,可之前调用onCreate()的活动的方法已经完成。 You have onActivityCreated() callback in your fragment and onCreateView() . 您的片段和onCreateView()onActivityCreated()回调。 You can use any of it - it executes after onCreate method of activity. 您可以使用它中的任何一个 - 它在onCreate活动方法之后执行。

This bug can be reproduce by turning on "Dont't keep activities" in developer options. 通过在开发人员选项中启用“不要保留活动”,可以重现此错误。 I've encountered similar issue as well and solved using solution provided by FunkTheMonk. 我也遇到了类似的问题,并使用FunkTheMonk提供的解决方案解决了。

Recently ran in to the problem. 最近遇到了这个问题。 See stack trace in the bottom. 请参阅底部的堆栈跟踪。

As FunkTheMonk have stated, the crash is due to the fact that your customized onCreate() code in your Activity (right after super.onCreate()) is executed after your customized onCreate() code in your Fragment (right after super.onCreate()) 正如FunkTheMonk所说,崩溃的原因是您的Activity中的自定义onCreate()代码(在super.onCreate()之后)在您的Fragment中定制的onCreate()代码之后执行(紧跟在super.onCreate之后) ))

If you really need your callback be promisingly executed after the whole Activity's onCreate(), put your code fragments in onActivityCreated() rather than onCreate() 如果您确实需要在整个Activity的onCreate()之后执行回调,请将您的代码片段放在onActivityCreated()而不是onCreate()

Otherwise the aforementioned condition will happen when your memory is low and the activity is recycled. 否则,当您的内存不足并且活动​​被回收时,将发生上述情况。

Per my experience, when my MyActivity sends an intent, the App crashes once I returned to MyFragment by pressing back key. 根据我的经验,当我的MyActivity发送一个意图时,一旦我通过按回键返回MyFragment,应用程序崩溃了。

Caused by: java.lang.NullPointerException
   at MyFragment.onCreate(MyFragment.java:20)
   at android.support.v4.app.Fragment.performCreate(Fragment.java:1939)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1029)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1230)
   at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:2037)
   at android.support.v4.app.FragmentController.dispatchCreate(FragmentController.java:154)
   at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:289)
   at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:58)
   at MyActivity.onCreate(MyActivity.java:129)
   at android.app.Activity.performCreate(Activity.java:5248)
   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2162)
   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257) 
   at android.app.ActivityThread.access$800(ActivityThread.java:139) 
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210) 
   at android.os.Handler.dispatchMessage(Handler.java:102) 
   at android.os.Looper.loop(Looper.java:136) 
   at android.app.ActivityThread.main(ActivityThread.java:5086) 
   at java.lang.reflect.Method.invokeNative(Native Method) 
   at java.lang.reflect.Method.invoke(Method.java:515) 
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) 
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) 
   at dalvik.system.NativeStart.main(Native Method) 

I may be too late to answer but still. 我可能来不及回答但仍然。 I encountered this a few days ago. 我几天前遇到过这个。 It happens when you are using dynamic fragments and in the layout you use the fragment tag to display the fragment. 当您使用动态片段时会发生这种情况,并且在布局中使用片段标记来显示片段。 Instead use a Layout (preferably FrameLayout). 而是使用布局(最好是FrameLayout)。 Assuming you were using the support fragment library. 假设您使用的是支持片段库。

It is worth a try. 值得一试。

As many stated this happens when using <fragment/> tag in xml. I used it for navigation component at first but later Android Studio suggested to change it to <androidx.fragment.app.FragmentContainerView/> .正如许多人所说,在 xml 中使用<fragment/>标签时会发生这种情况。我最初将它用于导航组件,但后来 Android Studio 建议将其更改为<androidx.fragment.app.FragmentContainerView/>
After applied the change activity was called first and afterwards the fragments.应用后,首先调用更改活动,然后调用片段。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM