22

Recently I came across a hard to reproduce issue. The NPE occurs when a fragment tries to initialize ArrayAdapter with the data from Activity. The default list initialized in Activity's onCreate method:

 @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():

@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. The reason is that mAccounts is null. The issue appears seldom and I wasn't able to reproduce it.

When is it possible that fragment's onCreate() is called before activity's onCreate()? According to the source code, Fragment's onCreate() is dispatched in the Activity's onCreate(). Why is is it then called after Activity's onCreate() has finished its execution?

k_shil
  • 2,108
  • 1
  • 20
  • 25
  • no it is not possible. – Blackbelt May 18 '15 at 08:09
  • You should post more code about how your fragment shows in your activity. – jobcrazy May 18 '15 at 08:14
  • I agree with @Ilya Vorobiev. The fragment's onCreate() is dispatched when super.onCreate() of the activity is called. The question is why in majority of cases it is executed after the Activity's onCreate. – k_shil May 18 '15 at 09:04
  • 1
    Old thread, but it still bites the unwary. It's a question of whether `savedInstanceState` is null. On normal first use, it is null. In that case super.onCreate() doesn't do much, and when you create your child Fragments their onCreate() gets called. But if the Activity is destroyed/saved, Activity#onCreate() is called with a non-null `savedInstanceState`. Now super.onCreate() rehydrates all the Fragments and calls their onCreate(), before Activity#onCreate has completed. Moral: avoid doing anything in Fragment#onCreate because you don't know what state the parent Activity lifecycle is in. – Ben Apr 28 '22 at 17:50

6 Answers6

14

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()

FunkTheMonk
  • 10,908
  • 1
  • 31
  • 37
  • Thanks for the tip. There are definitely several ways to solve the issue. The question is why the behavior is different. How is the onCreate() triggered exactly and why it sometimes happens after activity's onCreate(). – k_shil May 19 '15 at 10:50
7

onCreate() of your fragment can be called before onCreate() method of your activity has been finished. You have onActivityCreated() callback in your fragment and onCreateView(). You can use any of it - it executes after onCreate method of activity.

Ilya Vorobiev
  • 836
  • 8
  • 16
  • Do you know the exact circumstances? As I mentioned the issue is reproduced rarely. – k_shil May 18 '15 at 08:25
  • 2
    There are a lot of situations when this issue takes place. If you take a look on onCreate() method of FragmentActivity you will see that activity firstly attaches itself to fragments, then executes super.onCreate(). So there is no guarantee that your code will be executed before your fragment's onCreate(). – Ilya Vorobiev May 18 '15 at 08:33
  • 1
    Well I would understand it when the issue is 100% reproducible since indeed onCreate() of my fragment is called before onCreate() of the activity. I guess I should edit the question. It should be reversed. Why is fragment's onCreate() called after activiy's onCreate() even though it is dispatched in Activty's onCreate(). – k_shil May 18 '15 at 08:59
  • 5
    Normally that happens when a fragment is restored due to an activity recreation. When you first init the activity you manually create the fragments (after super.onCreate()) but when the activity is recreated fragments are recreated in some code in super.onCreate(). – lujop Jun 28 '17 at 13:16
  • onActivityCreated is deprecated you can now use onViewCreated(View, Bundle) or lifecycle observer of an activity – Rax Apr 24 '23 at 11:01
6

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.

kopikaokao
  • 500
  • 7
  • 13
6

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())

If you really need your callback be promisingly executed after the whole Activity's onCreate(), put your code fragments in onViewCreated (since onActivityCreated() is deprecated) rather than 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.

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) 
hata
  • 11,633
  • 6
  • 46
  • 69
Teng-pao Yu
  • 1,313
  • 15
  • 30
  • You are right!!! In my case I spent almost two days trying to reproduce this situation on a real device. Finally I saw that this happens when memory is low! In order to reproduce it I launched several memory consuming apps and after that launched my app and I encountered that strange behavior again. – porlicus Mar 03 '23 at 15:19
1

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). Assuming you were using the support fragment library.

It is worth a try.

vishal-wadhwa
  • 1,021
  • 12
  • 18
0

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/>.
After applied the change activity was called first and afterwards the fragments.

Hanako
  • 1,637
  • 1
  • 13
  • 16