Android best tip to work with fragments and orientation change.

Recently I read about Lars Vogel’s tutorial on fragments. Where (Or probably in his Google+ post) he has told about headless fragments – the fragments without heads(UI). According to him such fragments with setRetainInstance(true); will save our purpose where we use fragment and orientation and downloading or getting data needs time.

Traditionally where android was only activities manifest was our friend. Where in manifest we either lock orientation or add android:configChanges to listen to orientation change and literally do nothing. The first idea is being rejected throughout the years by android development community. And while introducing fragment, to provide UI and UX flexibility throughout configuration changes android developers already nullified the second solution of android:configChanges, it still works, unless you have defined your landscape UI in layout-land folder. It won’t called while your configuration is changed.

The headless fragment solution applies at the place where none of the above stated solution works for our problems. And here I am going to explain it with code.

The key of the solution is lied in sample code. In api demos. Refer to com.example.android.apis.app.FragmentRetainInstance.java file Where they have used a parent activity, a UI fragment and a headless fragment.

Based on this example let’s create the headless fragment.

Before we start we assume that you already know some basics of the fragments api. If not it’s better to get some knowledge of it. We are not covering it here because it’s too broad to cover for one post.

Second, this example covers a case where UI fragment is a list fragment and our headless fragment depends on this fragment. You are free to modify this example for your need and use-cases.

Step 1-

UI Fragment: Check whether we have already created the fragment, if yes leave it aside.

By below code

FragmentManager fragmentManager = getFragmentManager();
HeadlessFragments fragment = (HeadlessFragments) fragmentManager                
                      .findFragmentByTag(HeadlessFragments.TAG);

After this, fragment will be null if destroyed or creating for first time.

Step 2-

UI Fragment: If fragment is null on Step 1, initialize it.

By below code

        if (fragment == null) {
            fragment = new HeadlessFragments();
            fragment.setTargetFragment(this, 10);
            fragmentManager.beginTransaction().add(fragment,
                    ContactsListHeadlessFragments.TAG).commit();
        }

These are the lines we must enter to start our headless fragment properly, apart from that you can add some listeners in headless fragment, which will notify to UI fragment about current task status.

Step-3

Headless fragment : onCreate

Keep in mind the headless fragment has two important aspects. 1: It doesn’t have UI. 2. It retains its state throughout configuration changes.

Part 1 will be covered in next step. Here we are going to cover part 2.

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        //The heart and mind of headless fragment is below line. It will keep the fragment alive during configuration change when activities and   //subsequent fragments are "put to death" and recreated
        setRetainInstance(true);

        performLongAction();
    }

Step-4

HeadlessFragment : If you have onCreateView overridden in your headless fragment, return null.

However this step is optional. In a practice I don’t override onCreateView at all. And it still works. So we don’t have any code here.

Notes:

  • In case you need context to work with resources, on handy (not necessarily the best) place to get this is onActivityCreate() method. However if you have set target fragment properly in UI fragment you can do it virtually anywhere.
  • This method is not fool proof. We have to take care when UI fragment is destroyed (mostly because we have moved in other fragment-activity or our parent activity is onPause, among other reasons) and our headless fragment is still doing some operations. It will throw exception.