Tuesday, March 2, 2010

Handling portrait/landscape switch in Android

When you develop an Android application, you will notice that when the user changes the orientation of the device, the UI framework will recreate the current screen layout with the corresponding UI objects. The framework calls these methods of the current activity: onPause, onStop, onDestroy, and then onCreate, onStart, onResume to display the activity again. The onCreate method of the activity retrieves the data it displays from a database and populates the input fields with the private populateFields method.
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  /* UI setup here */
          
  Uri itemUri = getIntent().getData();
  if (newRecord) {
    customer = new Customer();
  } else {
    customer = retrieveCustomer(itemUri);
  }

  populateFields(customer);
}
When the user switches orientation, the Android framework will destroy this activity and call onCreate again, which will retrieve the data and populate the input fields. The result is that the user will lose entered data, because this input fields will contain what the activity retrieved from the database. A solution is to store the entered data in the database in the onPause method:
protected void onResume() {
  copyFromInput(customer);
  if (newRecord) {
    saveCustomer(customer);
  } else {
    updateCustomer(customer);
  }

  super.onResume();
}
This solution mostly works and also takes care of automatic saving the entered data when the user uses the "home" button. This may also surprise the user, since the data is saved without the user explicitly asking to save it. A better solution is to use the savedInstanceState parameter that the Android framework passes into the onCreate method. This parameter is null when the user navigates to the activity. When the user changes orientation of the Android device, the framework destroys the activity after saving the contents of the input fields in a Bundle object. When the framework recreates the activity after an orientation change, the savedInstanceState parameter is not null and contains all the data that your application would want save during this change. The Android framework already automatically saves and restores the contents of the input fields, so your application does not need to do this. The thing that your application needs to be aware of is that it should only set the contents of the input fields when the savedInstanceState parameter is null.
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  /* UI setup here */
          
  Uri itemUri = getIntent().getData();
  if (newRecord) {
    customer = new Customer();
  } else {
    customer = retrieveCustomer(itemUri);
  }
  
  if (savedInstanceState == null) {
    populateFields(fragment);
  }
}