Tuesday, May 6, 2014

Fragment lifecycle with respect to its Activity

What is Fragment?

Fragment represents a behavior or a portion of user interface in an ActivityWe 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

Origin : http://developer.android.com/guide/components/fragments.html#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.

2 comments :

  1. I think that your "Fragment lifecycle with respect to its Activity" is totally wrong.
    This 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?

    ReplyDelete
    Replies
    1. Hi Przemysław Luśnia,

      Thanks 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

      Delete