Headless Fragments To Handle Orientation Change In Android

Posted By : Daljeet Singh | 12-Feb-2018

While building android applications that work in both the portrait and landscape orientation modes,a major cause of concern is saving the activity state as the activity is destroyed and created again in case of a configuration change.

To handle the activity restart and restore the activity state, android provides us with a number of options.Some of these are :

  • Using onSaveInstanceState() : The onSaveInstanceState() method is called by android before destroying the activity,so this can be used to save the application state data.The data can be restored in the onRestoreInstanceState() or the onCreate() method of the activity upon restart using the system provided Bundle.The state of views that have an id is handled by the default implementation of onSaveInstanceState() provided by android,which also saves the id of the currently focussed view.We can store additional information in the system provided Bundle, to restore in case of an activity restart.

  • Using configChanges to handle configuration change : Android provides us with an option to handle the configuration change ourself by including the attribute android:configChanges for the activity inside the manifest and specifying an appropriate value(which in our case would be "orientation").This prevents the activity restart when the orientation of the device is changed and instead calls the onConfigurationChanged().This method receives a Configuration object which specifies the new configuration for the device.We can make use of this Configuration object to update the resource values appropriately according to the orientation.The use of this approach to handle orientation change is usually discouraged, as the configuration changes can occur for different reasons such as changing the default language,keyboard availability etc. and these will still cause the activity to be destroyed and restarted.

  • Using Headless Fragments : The onSaveInstanceState() method works fine for restoring smaller sets of data in the activity.However,if our application needs to restore large or complex data sets this method may result in slower performance of the app.Also,handling network calls across change in orientation is not feasible with the onSaveInstanceState() method as the activity ,for which the callback from the network call holds the reference, is destroyed after the change in orientation and the results will not be reflected in the newly created activity.

    To solve the above mentioned problems,headless fragments come in handy.Headless fragments are fragments that do not have any UI.We can retain the current instance of a headless fragment over orientation change by calling setRetainInstance(true) inside the fragment(usually in the onCreate for the fragment as it is only called once for the fragment).We define the data object to be retained across orientation change inside the headless fragment,define setter and getter methods for it and consequently use the fragment manager to add the headless fragment to our activity.We can obtain this data object from the headless fragment when the activity restarts due to change in orientation.

    Similarly, we can also use a headless fragment to handle network calls across the orientation change.Instead of making the network call from our activity,we make it from the headless fragment and receive the callback in the headless fragment itself.From there on,we can assign a callback to our activity with the response.The sample code for such a request is shown below :

    In our activity :
            /*obtaining the headless fragment object if it exists,else create a new object*/ 
    
    	FragmentManager fm = getFragmentManager();
            MainTaskFragment mainTaskFragment = (MainTaskFragment) fm.findFragmentByTag("main_task_fragment");
            if (mainTaskFragment == null) {
                mainTaskFragment = new MainTaskFragment();
                fm.beginTransaction().add(mainTaskFragment, "main_task_fragment").commit();
                }
    
    Inside the headless fragment :
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setRetainInstance(true);
        }
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
            GithubApi githubApi=new GithubApi(MainTaskFragment.this);
            githubApi.GithubApiCall("daljeet33");
            return null;
        }
    
    Here GithubApi is a class that makes a network request to a Github api through retrofit and receives the response.This response is received in the headless fragment through a callback from where it can be further passed on to the activity through another callback.

    The reason the headless fragment is able to maintain network calls over orientation change is because it always holds the reference to the current activity.If an activity is restarted due to orientation change during a network call,it goes through its normal lifecycle events and upon creation its instance is passed to the onAttach() method of the headless fragment.Also, the lifecycle methods are executed in batches inside a single message in the message queue of the main thread,so the callback methods cannot be called between the onDestroy() and onCreate() methods of the activity while it is restarted.Since the onDestroy method is never called upon the fragment due to calling setRetainInstance(true),it always holds the reference to the activity.

About Author

Author Image
Daljeet Singh

Daljeet has experience developing android applications across a range of domains such as Cryptocurrency, Travel & Hotel Booking, Video Streaming and e-commerce. In his free time, he can be found playing/watching a game of football or reading up on either

Request for Proposal

Name is required

Comment is required

Sending message..