The system will save and restore the state of the UI elements that the user can change but it will not store any that your code changes. It also doesn't automatically save and restore any other data that the user or your code may have generated that isn't within the UI.
In these cases you have to write some code that saves the values and restores them.
There are lots of ways of saving the the state of an app as it is started and stopped by the system. One of the simplest is to ue the Bundle object that the system uses.
The system fires the onSaveInstanceState event when it is about to add data to the Bundle and save it. If you want to save some additional data all you have to do is override the default event handler.
For example, suppose you want to save and restore the data in the TextView in the Lifecycle explorer. First you have to save the data:
Notice that we save the text content of the textView object as the value and use the key "myText". In most cases it would be better to create a string constant for the key. The key can be any identifier you care to use but it has to be unique within the Bundle as it is used to retrieve the data you have stored in the Bundle.
Now to retrieve the data and place it into the TextView we need to change the onCreate event handler:
This starts off in the usual way but now we check to see if savedInstanceState has any data. If it does we retrieve the stored text using the key "myText".
There is no reason not to use the onCreate event handler in this way but the system also fires an onResetoreInstanceState event when it is about to perform its own "automatic" restore of the UI for you. You can override this event handler if you want to keep the state restore code out of the onCreate event handler. For example you could have written:
Do remember to call the super.onRestoreInstanceState if you want the system to restore the rest of the UI in the usual way.
There are put and get methods for a range of standard data types. All simple types byte, integer and so on are supported as are strings, arrays and other simple data structures. You can also create your own classes that can be stored in a Bundle by implementing the Parcelable Interface.
Notice you can save arbitrary data and not just data for the layout. You can also create your own Bundle instance and make use of it for data storage, persistence and for transferring data to other parts of a program. There are many standard classes the Bundle doesn't support. In these cases you have to make your own arrangements to save data to storage.
Often all you need to do to make sure that your app maintains its state between system restarts is to use the savedInstanceState Bundle object.
This approach also reduces much of the practicality of lifecycle management to implementing the onSaveInstanceState and onRestoreInstanceState event handlers. This is so much simpler than having to worry about all of the different lifecycle events.
As an exercise you can now go back to iCalc introduced in the previous chapter and make its display and current value persist through a screen rotate.
Complex UI Elements
One of the traps waiting for you is the problem of exactly what is automatically saved and restored.
For example at the start of this chapter we have the story of the app that lost the users form data when it was rotated.
Given what we know know of the auto-saving and restoration of user modifiable UI elements you might be wondering how this could happen?
The answer is that the programmers of the app had probably grown accustom to the automatic persistence of UI state and didn't bother to check that rotation had no effect. It did have an effect because the form was being down loaded from a web site and displayed in a WebView control. A WebView control is persisted by the system but it reloads the page when it is restored. This means that on a rotation the form was reloaded as empty and the users data was lost.
You always have to check that things work as you expect. Always test what happens to your UI on a rotation.
Advanced State Management
For completeness it is worth noting that there are many more approaches to maintaining state. Later you will need to discover how to store lots of user data locally for longer term persistence and this is often enough to implement state management though a configuration change.
There are also more advanced state management problems when you come to make use of Fragments - the subject of Mastering Fragments.
In this case you can use setRetainedInstance to ask the system not to destroy an entire Fragment. This means that all of the data stored in the Fragment is retained even though the Activity may be removed from memory. This makes it possible to use a Fragment as a repository of state.
The ultimate in making sure that things happen as you want it to handle the configuration change yourself.
You can do this by making a change to the manifest. If you do this then it is up to you to make the changes needed when the onConfigurationChanged even occurs. You could for example opt to animate buttons and other UI objects into new positions or just ignore the need to reconfigure altogether.
This is all advanced and for most applications you can get by using just the onSaveInstanceState and onRestoreInstanceState event handlers.
Android, like many other mobile OSs, will remove your app from memory and restart it as it needs to.
The user will not be aware that your app has been destroyed and recreated and will expect it to continue from where they left off.
The system signals changes in state to your Activity via a complicated set of events. You need to understand how these work in order to make your Activity resume correctly after the various levels of suspension.
The system will store the state of any user modifiable UI components and restore it for you when your Activity resumes.
The data is stored in a special instance of Bundle called savedInstanceState.
The system alerts you when it is about to save and restore data from savedInstanceState by firing the onSaveInstanceState and onRestoreInstanceState event handlers.
You can override both of these event handlers to save and restore extra data in the savedInstanceState Bundle.
For many simple apps you can mostly ignore the life cycle events and concentrate on using the onSaveInstanceState and onRestoreInstanceState event handlers to persist data.
You must always check that UI and other elements are persisted through a suspension of your app. You can test using a rotation configuration change.
There are other more advanced ways of saving state and these you need to discover later on. You can't use a Bundle for everything.
From life cycle and persistence we now can turn out attention to some of the more advanced UI elements.
You can download the code for this program from the CodeBin. (Note, you have to register first).