What
is Fragment?
A Fragment represents
a behavior or a portion of user interface in an Activity.
We can combine multiple fragments in a single activity to build a
multi-pane UI and reuse a fragment in multiple activities.
The Fragment
class has code that looks a lot like an Activity.
It contains callback methods similar to an activity, such as onCreate(), onStart(), onPause(),
andonStop().
In fact, if you're converting an existing Android application to use fragments,
you might simply move code from your activity's callback methods into the
respective callback methods of your fragment.
Fragment
Lifecycle
Fragment
lifecycle with respect to its Activity
Fragment's lifecycle is tied to its owning activity and the normal flow of fragment in a activity.
1.
MainActivity onCreate
Fragment onAttach
Fragment onCreate
Fragment onCreateView
Fragment onViewCreated
Fragment onActivityCreated
2.
MainActivity onStart
Fragment onStart
3.
MainActivity onResume
Fragment onResume
Fragment onStop
4.
MainActivity onStop
Fragment onDestroyView
Fragment onDestroy
Fragment onDetach
5.
MainActivity onDestroy
What happens? If we navigates to another activity from fragment and come back to main activity?
Here we have
two scenarios, where fragment life cycle works.
1.
Activity is not destroyed when user
leaves it.
2. Activity
got destroyed when user leaves it.
Activity
Normal flow
|
Activity
got destroyed
|
MainActivity
onCreate
Fragment onAttach
Fragment onCreate
Fragment onCreateView
Fragment onViewCreated
Fragment onActivityCreated
MainActivity
onStart
Fragment onStart
MainActivity
onResume
Fragment onResume
|
MainActivity
onCreate
Fragment onAttach
Fragment onCreate
Fragment onCreateView
Fragment onViewCreated
Fragment onActivityCreated
MainActivity
onStart
Fragment onStart
MainActivity
onResume
Fragment onResume
|
Fragment onStop
MainActivity
onStop
|
Fragment onStop
MainActivity
onStop
Fragment onDestroyView
Fragment onDestroy
Fragment onDetach
MainActivity
onDestroy
|
MainActivity
onRestart
MainActivity
onStart
Fragment onStart
MainActivity
onResume
Fragment onResume
|
Fragment onAttach
Fragment onCreate
MainActivity
onCreate
Fragment onCreateView
Fragment onViewCreated
Fragment onActivityCreated
MainActivity
onStart
Fragment onStart
MainActivity
onResume
Fragment onResume
|
In the above
differentiation, the 2nd and 3rd row tells the flow of life cycle of
fragment with respect to its activity.
By this flow
change, we should be aware in writing our business logics.
Why, we should be aware?
Example:
Assume, we have a custom action bar header, we are modifying the header depend
upon the fragment selection in the fragment.
The custom
header is called in the MainActivity Oncreate method as follows
ActionBar bar = getActionBar();
if
(bar != null) {
bar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP |
ActionBar.DISPLAY_SHOW_CUSTOM |
ActionBar.DISPLAY_SHOW_HOME |
ActionBar.DISPLAY_USE_LOGO);
bar.setCustomView(R.layout.custom_header);
}
// enable ActionBar app
icon to behave as action to toggle nav drawer
bar.setDisplayHomeAsUpEnabled(true);
bar.setHomeButtonEnabled(true);
In fragment,
the custom header is updated as follows.
Create
instance of the activity in fragment to update the action bar header.
onAttach(Activity)called once the fragment is associated with its activity.
So, we can assign our variable inside the onAttach
public
MainActivity activity;
@Override
public void
onAttach(Activity activity) {
Log.d("CHECK", "
Fragment onAttach");
super.onAttach(activity);
this.activity =
(MainActivity) activity;
}
activity.updateActionBarHeader(activity.getTitle().toString());
Usually, we will be setting headers in onCreate of activity or
fragment, Since onCreate(Bundle)called to do initial creation of the fragment.
Application
launches and works fine, when we placed the updateActionBarHeader in
onCreate, but when application navigated from fragment and returns back, the
application crashes if the activity is destroyed and the exception thrown as
follows.
FATAL
EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo
{PACKAGE_NAME/MainActivity}: java.lang.NullPointerException
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at
android.app.ActivityThread.access$600(ActivityThread.java:130)
at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at
android.os.Handler.dispatchMessage(Handler.java:99)
at
android.os.Looper.loop(Looper.java:137)
at
android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native
Method)
at
java.lang.reflect.Method.invoke(Method.java:511)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native
Method)
Caused by: java.lang.NullPointerException
at
MainActivity.updateActionBarHeader(MainActivity.java:232)
at
MainActivity$PlanetFragment.onCreate(MainActivity.java:276)
at
android.app.FragmentManagerImpl.moveToState(FragmentManager.java:796)
at
android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1035)
at
android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1017)
at
android.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:1797)
at
android.app.Activity.onCreate(Activity.java:886)
at
MainActivity.onCreate(MainActivity.java:80)
at
android.app.Activity.performCreate(Activity.java:5008)
at
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
... 11 more
So, don't try
to put the logic of updating action bar in onCreateView rather than onCreate of
fragment and avoid the crash.
Thanks for reading :)
Whether this post is helpful?
Have something to add to this post? If you have any other quick thoughts/hints that you think people will find useful? Share it in the comments.
java.lang.RuntimeException: Unable to start activity ComponentInfo {PACKAGE_NAME/MainActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
at android.app.ActivityThread.access$600(ActivityThread.java:130)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at MainActivity.updateActionBarHeader(MainActivity.java:232)
at MainActivity$PlanetFragment.onCreate(MainActivity.java:276)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:796)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1035)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1017)
at android.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:1797)
at android.app.Activity.onCreate(Activity.java:886)
at MainActivity.onCreate(MainActivity.java:80)
at android.app.Activity.performCreate(Activity.java:5008)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
... 11 more
I think that your "Fragment lifecycle with respect to its Activity" is totally wrong.
ReplyDeleteThis is not what I observed on Moto G 4.4.4. I commited new fragment in MainActivity.onCreate() method.
I observed:
A.onCreate
A.onStart
F.onAttach
F.onCreate
F.onCreateView
F.onViewCreated
F.onActivityCreated
F.onStart
...
Situation you're talking about is if you create fragment straight from XML. But only for starting the fragment, eg.:
A.onCreate
F.onAttach
F.onCreate
F.onCreateView
F.onViewCreated
A.onStart
F.onActivityCreated
F.onStart
...
But when it comes to onStop, then not Fragment's onStop is the first, but Activity's onStop is. The same with onDestroy. In both fragment creation situations.
By the way, the XML way of creating fragment is not recommended because Fragments are not so flexible then: they cannot be replaced or removed at runtime.
How did you create this table?
Hi Przemysław Luśnia,
DeleteThanks for the comments.
1. I am not taking about the fragment declaring in the xml and In the post also I haven't mentioned anything about the declaration.
2. The table shown above is by putting the log statements in the activity and fragments.
3. I have tested in moto G2 4.4.4 & Moto G2 5.0.2
But when it comes to onStop, then not Fragment's onStop is the first, but Activity's onStop is. The same with onDestroy. In both fragment creation situations.
The above statement is wrong. First fragment will be onStop and then follows by activity.
for your ref: you can download the project and check from the following location
https://github.com/harshavardhands/FragmentWithRespectToActivityLifeCycle