Fragments are funny things but, so I thought, once you know their quirks they're an invaluable tool for writing good code across multiple devices.
However, while fixing an orientation change bug I've run up against a wall. For my fragment to work it needs access to a View which belongs to it's containing Activity leading me on a merry chase trying to find how the Activity & Fragment lifecycles interact.
I'm adding a fragment to my Activities view in it's onCreate()
method:
// Only add a fragment once, as after it's been added it cannot be replaced (Even though there is a .replace() method. Which is a massive gaping hole in fragments as a technology if you ask me)
if(savedInstanceState == null) {
MainMenuFragment menu= new MainMenuFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.menuFrame, menu);
transaction.commit();
}
Leading to this Activity->Fragment Lifecycle:
01-04 15:17:27.226: W/SinglePaneActivity 0: onCreate()
01-04 15:17:27.378: W/MainMenuFragment 0: onAttach() to SinglePaneActivity 0
01-04 15:17:27.378: W/MainMenuFragment 0: onCreate()
01-04 15:17:27.453: W/MainMenuFragment 0: onActivityCreated()
01-04 15:17:27.476: W/MainMenuFragment 0: onStart()
01-04 15:17:27.476: W/SinglePaneActivity 0: onStart()
01-04 15:17:27.476: W/SinglePaneActivity 0: onResume()
01-04 15:17:27.476: W/MainMenuFragment 0: onResume()
An orientation change however highlights that this isn't usually the case, A fragments onCreate()
method isn't called after it's parent Activities onCreate()
. Infact, the first lifecycle call of a Fragment's onAttach()
occurs before the Activity has even been created (null
is passed as an argument):
01-04 15:10:49.589: W/MainMenuFragment 0: onPause()
01-04 15:10:49.589: W/SinglePaneActivity 0: onPause()
01-04 15:10:49.589: W/MainMenuFragment 0: onStop()
01-04 15:10:49.589: W/SinglePaneActivity 0: onStop()
01-04 15:10:49.589: W/MainMenuFragment 0: onDestroyView()
01-04 15:10:49.589: W/MainMenuFragment 0: onDestroy()
01-04 15:10:49.589: W/MainMenuFragment 0: onDetach()
01-04 15:10:49.609: W/SinglePaneActivity 0: onDestroy()
01-04 15:10:49.617: W/MainMenuFragment 1: onAttach() to null
01-04 15:10:49.617: W/MainMenuFragment 1: onCreate()
01-04 15:10:49.617: W/SinglePaneActivity 1: onCreate()
01-04 15:10:49.890: W/MainMenuFragment 1: onActivityCreated()
01-04 15:10:49.917: W/MainMenuFragment 1: onStart()
01-04 15:10:49.917: W/SinglePaneActivity 1: onStart()
01-04 15:10:49.921: W/SinglePaneActivity 1: onResume()
01-04 15:10:49.921: W/MainMenuFragment 1: onResume()
I have absolutely no idea why this is occuring. Could anyone shed any light on why Fragment.onAttach()
is being called before it's containing Activity has been created?
Fragments I've got which don't need access to their containing activity (until UI interaction) work as expected.
Argh,
01-04 15:46:23.175: W/MainMenuFragment 0: onAttach() to SinglePaneActivity 0
01-04 15:46:23.179: W/MainMenuFragment 0: onCreate()
01-04 15:46:23.246: W/MainMenuFragment 0: onActivityCreated() with Activity SinglePaneActivity 0
01-04 15:46:23.269: W/MainMenuFragment 0: onStart()
01-04 15:46:23.269: W/SinglePaneActivity 0: onStart()
Why the heck there is an onAttach()
method I have no idea. Especially since "attach" happens before there is an Activity.
The method I needed was of course, onActivityCreated()
which happens as the final call in the "Creation" set of Fragment lifecycle events.