sil2100//vx developer log

Welcome to my personal web page

Empty

Android app: state persistency on orientation change

Parts of my latest interests tend to lean towards Android - both application and system development. There was one thing I noticed lately: whenever orientation changes, the activity gets restarted and might lose its state. This happens because Android has a strange policy of forcing the recreation of the activity whenever the configuration changes - such as orientation, language etc. So if we don't want our application starting off clean on every device tilt, well, we need to prepare it for this evil.

2012-10-26 22:34

For starters, as you probably know, an Android activity follows the following 'very simplified' lifecycle:

  1. onCreate()
  2. onStart()/onRestart()
  3. Application running
  4. onResume()/onPause()
  5. onStop()
  6. onDestroy()

When a configuration changes, the Activity just gets killed, so we reach the actual end of the lifecycle - i.e. onDestroy(). But right before onDestroy() is called, we are given a chance to save the current state of the application with onSaveInstanceState(), an useful overridable method for our cause. By deriving from this method, we can actually store the state temporarily by using the Bundle outState object that's being passed as an argument. A Bundle is a very practical type - it's a pre-made Parcelable that we can use to store data and/or Parcelables associated with string keys.

So, we actually are given a multi-type hash-table-like object to store our settings. On each onCreate() we are also being passed a Bundle, which in case of a configuration change restart is actually the outState one we fill by ourselves. So, for example:


 public class FooActivity extends Activity {
   // The usual convention is to first include creation methods, but here we'll do an
   // exception for readability's sake
   
   // End of application
   @Override
   public void onSaveInstanceState(Bundle outState) {
     // We can just insert simple types right away, such as ints, floats and even Strings
     outState.putInt("important_integer", importantInteger);
     outState.putFloat("ble", shyFloat);

     // But we can also include Parcelables, e.g. other Bundles
     // Let's imagine a childClass object that has a method that saves its internal state
     // by creating a new Bundle, saving its state and returning it as the result

     // We can take that and just slam it to the state bundle
     outState.putParcelable("child", childClass.saveYourInstance());
   }

   // (...) Rest of code here (...)

   // Start of application
   @Override
   public void onCreate(Bundle savedInstanceState) {
     if (savedInstanceState != null && savedInstanceState.size() > 0) {
       // Seems like we have a state we can start from
       importantInteger = savedInstanceState.getInt("important_integer");
       shyFloat = savedInstanceState.getFloat("ble");

       // Our smart SomeSmartCustomChildClass has a custom constructor that can restore
       // its state from a bundle, so we have it nicely divided
       childClass = new SomeSmartCustomChildClass(savedInstanceState.getParcelable("child"));

       // (...)
     }
     else {
       // Normal Activity initialization from zero

       // (...)
     }
   }


   private int importantInteger;
   private float shyFloat;
   private SomeSmartCustomChildClass childClass;
 }

We're missing some checks and bits-and-pieces here, but it's just an exemplary piece of code to demonstrate how saving and restoring the application state can be realized.

A tip: when you start designing any application, start off from the very beginning by defining what will compose the state of your Activity. What are the defining variables? What are the elements that define the current user state? Once you have this planned, start implementing the save (onSaveInstanceState) and restore state chunks of code from the very beginning. Whenever you have a new variable defining your state, add it to save/restore right away - later on you're more likely to forget, make a mistake or lose interest and motivation to do so. It's not really motivating to suddenly write Parcelable code for 30 variables and 10 lists.
At least not for me.

A bit unrelated - I'm in Copenhagen right now and will be around for UDS (Ubuntu Developer Summit), so you can always poke me if you're attending it as well. Till later!