5

According to the docs

A fragment transaction can only be created/committed prior to an activity saving its state. If you try to commit a transaction after Activity.onSaveInstanceState() (and prior to a following Activity.onStart or Activity.onResume(), you will get an error.

I can understand that the first part that a fragment transaction can't committed after Activity.onSaveInstanceState(), because the state after the commit can be lost if the activity needs to be restored.

But I don't understant why we can't commit a fragment transaction prior to a Activity.onStart or Activity.onResume()? Oncreate() is also prior to Activity.onStart or Activity.onResume().Does it mean that we can't even commit it in oncreate()?

Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
user3591494
  • 159
  • 3
  • 8

3 Answers3

6

The key here is that you can't commit a transaction after a call to onSaveInstanceState() and prior to a following onStart() or onResume().

You can commit transactions just fine on the initial onCreate() and a subsequent onStart() or onResume() because there is no state.

However, if the Activity is restoring its state (i.e. onSaveInstanceState() was previously called, and the Activity is recreating itself with that state, you cannot perform a Fragment transaction. This is because if you commit a Fragment transaction prior to the Activity restoring the previous Fragment state, you end up in a situation where it is unclear what state you are in. Does the saved state take precedence over the new state that you have created by committing a Fragment transaction, or should the new transaction take precedence over the saved state?

The easiest way to check for this scenario is to check if the savedInstanceState bundle passed to onCreate() and other lifecycle methods is null. If it's null, there is no saved state and you are safe to perform your transaction. If it is not null, then there is saved state that you probable want to preserve.

Bryan Herbst
  • 66,602
  • 10
  • 133
  • 120
  • I don't understand why there's no state in onCreate()? Have the state not already been restored when the savedInstanceState bundle passed to onCreate()? We can retore the state in onCreate() or onRestoreInstanceState. – user3591494 Nov 08 '16 at 15:54
  • The state has not yet been restored in `onCreate()` because the Activity has just been created. For example, you haven't even created/set the content views yet, so there's nowhere for the saved views to go. You can restore *your* application state in `onCreate()` if you wish, but that doesn't mean that all other components have finished restoring their state. – Bryan Herbst Nov 08 '16 at 16:00
  • Does it mean that setContentView() is still running when Oncreate() completes, and it will continue to run till onResume() starts to run? – user3591494 Nov 09 '16 at 11:56
  • `setContentView()` is not still running when `onCreate()` completes. Typically that happens inside of `onCreate()`. View state however is just one example of state that might not have been restored yet when `onCreate()` is called. – Bryan Herbst Nov 09 '16 at 14:48
  • So content views have been set, savedInstanceState bundle(i.e., saved view state) has been sent to onCreate(),can you explain why view state has not been restored when onCreate() is called ? – user3591494 Nov 10 '16 at 13:38
  • Content views have *not* been set when `onCreate()` is called. Content views are usually inflated *during* `onCreate()`. It's a subtle but important difference and is the reason you can't assume state is restored at the beginning of `onCreate()`. Again, don't get too hung up on Views because they are just one piece of state that might be restored. `onRestoreInstanceState()` isn't even called until after `onStart()`, so any state being restored there (including the Activity's Window state) won't be restored until after that completes. – Bryan Herbst Nov 10 '16 at 14:37
  • So content views have been set, savedInstanceState bundle(i.e., saved view state) has been sent to onCreate(),can you explain why view state has not been restored when onCreate() is called ? – user3591494 Nov 11 '16 at 11:35
  • Content views have **not** bet set when `onCreate()` is called. I don't know how else to say it. The content views are set **during** `onCreate()`. The Activity's views are typically set by the *end* of `onCreate()`, but they have not been set at the *start* of `onCreate()`. – Bryan Herbst Nov 11 '16 at 14:14
1

It's safe any time before onSaveInstanceState(), which essentially means before onPause()/onResume(), and if your Activity ever went to onPause(), then it's safe only after onResume().

For example, during onActivityResult(), you haven't actually gone to after onResume(), so opening a dialog in onActivityResult() can crash.

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
0

Might want to bear in mind a committed transaction might not have executed.
This handles that:

getSupportFragmentManager().executePendingTransactions();
Jon Goodwin
  • 9,053
  • 5
  • 35
  • 54