Today we will discuss handling an activity or fragment’s state changes using onSaveInstanceState. So after you complete this lesson, you will be able to handle such State change for Activities. Although, if you want to handle your fragment state, you can follow the same as discussed below. However, at the end of this blog you will have a video tutorial. You could watch that.

onSaveInstanceState
Figure 1.1 – Example of a configuration change

In the Android system, there are a number of events that can trigger a configuration change. And the most prominent example is a change between portrait and landscape orientations when a configuration change occurs, the activity is destroyed and recreated. In such cases the original activity instance will have onPause(), onStop(), and onDestroy() callbacks triggered. And when a new activity instance will be created, it will have onCreate(), onStart(), and onResume() callbacks triggered. If you dig deeper into your activity lifecycle you will find other two methods – onSaveInstanceState and onRestoreInstanceState can be called but only if any configuration change happens. See Figure 1.2

Suppose an activity is in the foreground, and the user taps the Back button, the activity transitions through the onPause(), onStop(), and onDestroy() but onSaveInstanceState  and onRestoreInstanceState will not. Because the user intentionally pressed that button.



Activity Lifecycle about configuration changes

According to the below diagram onSaveInstanceState will be called before/after the onStop method and onRestoreInstanceState will be called in between onStart and on onResume. Therefore, we can save our UI data before the onDestroy using onSaveInstanceState and retrieve data from the onCreate method by using savedInstanceState bundle variable or we could just override onRestoreInstanceState method in our activity or fragment.

onSaveInstanceState
Figure 1.2 – Activity lifecycle while saving and restoring data

Remember

  • onSaveInstanceState – used to save data in a bundle called outstate.
  • onRestoreInstanceState – used to recover that data from savedInstanceState bundle.



Let’s Handle the configuration changes

In this example, we will handle one of the common configuration change such as screen rotation. As we can see In the below graphics there we have a button and a text view. The button will be incrementing a counter value and that value will be updated in the text view even if there have any configuration change happened.

activity-state-chage
Figure 1.3 – Example of a configuration change

Store data on configuration change

If you noticed, whenever the device is rotating counter value changed to ZERO and that’s why text view is also changed to ZERO. Alright, to save that state we will override onSaveInstanceState and store the counter value in outState variable like below snippet.

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("key_counter", counter);
}

Note: outstate is a bundle which requires key and value pair as it takes in onSaveInstanceState’s parameter.


Restore data on configuration change

When we have data in outState we can easily retrieve that data to restore the UI by simply overriding onRestoreInstanceState or get the data from onCreate method savedInstanceState.

  • Retrieving data from onRestoreInstanceState
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    counter = savedInstanceState.getInt("key_counter", 0);
    txtTotal.setText("" + counter);
}

  • Retrieving data from onCreate
    private int counter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
      
        counter = 0;
       if (savedInstanceState != null) {
            counter = savedInstanceState.getInt("key_counter", 0);
        } else {
            counter = 0;
        }
    }

Inside onRestoreInstanceState and onCreate method parameter we also have a bundle object called savedInstanceState which is actually holding all the outstate bundle’s data. And the above two snippets are just the two different places for retrieving data from the outState bundle.

Remember: when you are retrieving data from onCreate method you must have to check savedInstanceState != null otherwise you would have NullPointerException.

That’s it.


Test our Code

Now we have handled such configuration change in our app.

onSaveInstanceState
Figure 1.4 – OUTPUT: After Handling Activity State Changes

And that’s it for today. Next Shared Preferences.



Resources

Grab this complete MainActivity.java code

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "DailyCoding";
    private TextView txtTotal;
    private Button btnIncrement;

    private int counter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        txtTotal = findViewById(R.id.txt_total);
        btnIncrement = findViewById(R.id.btn_increment);

        counter = 0;

       /* if (savedInstanceState != null) {
            counter = savedInstanceState.getInt("key_counter", 0);
        } else {
            counter = 0;
        }*/

        txtTotal.setText("" + counter);

        btnIncrement.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                counter++;
                txtTotal.setText("" + counter);
            }
        });

    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("key_counter", counter);
    }

    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        counter = savedInstanceState.getInt("key_counter", 0);
        txtTotal.setText("" + counter);
    }
}


activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:padding="10dp"
    android:gravity="center">

    <TextView
        android:id="@+id/txt_total"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="0"
        android:textSize="80sp"/>

    <Button
        android:id="@+id/btn_increment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Increment Value"
        android:layout_below="@id/txt_total"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:textAllCaps="false"
        android:textSize="16sp"/>

</RelativeLayout>


Video Tutorial

Handle Activity State on Configuration changes

Complete Practical


Download this project to your local.


0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *