I've been working on the Android SDK platform, and it is a little unclear how to save an application's state. So given this minor re-tooling of the 'Hello, Android' example:
package com.android.hello;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class HelloAndroid extends Activity {
private TextView mTextView = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextView = new TextView(this);
if (savedInstanceState == null) {
mTextView.setText("Welcome to HelloAndroid!");
} else {
mTextView.setText("Welcome back.");
}
setContentView(mTextView);
}
}
I thought it would be enough for the simplest case, but it always responds with the first message, no matter how I navigate away from the app.
I'm sure the solution is as simple as overriding onPause
or something like that, but I've been poking away in the documentation for 30 minutes or so and haven't found anything obvious.
Meanwhile I do in general no more use
The life cycle is for most activities too complicated and not necessary.
And Google states itself, it is NOT even reliable.
My way is to save any changes immediately in the preferences:
In some way SharedPreferences work similar like Bundles. And naturally and at first such values have to be read from preferences.
In the case of complex data you may use SQLite instead of using preferences.
When applying this concept, the activity just continues to use the last saved state, regardless of whether it was an initial open with reboots in between or a reopen due to the back stack.
To help reduce boilerplate I use the following
interface
andclass
to read/write to aBundle
for saving instance state.First, create an interface that will be used to annotate your instance variables:
Then, create a class where reflection will be used to save values to the bundle:
Example usage:
Note: This code was adapted from a library project named AndroidAutowire which is licensed under the MIT license.
Simple quick to solve this problem is using IcePick
First, setup the library in
app/build.gradle
Now, let's check this example below how to save state in Activity
It works for Activities, Fragments or any object that needs to serialize its state on a Bundle (e.g. mortar's ViewPresenters)
Icepick can also generate the instance state code for custom Views:
You need to override
onSaveInstanceState(Bundle savedInstanceState)
and write the application state values you want to change to theBundle
parameter like this:The Bundle is essentially a way of storing a NVP ("Name-Value Pair") map, and it will get passed in to
onCreate()
and alsoonRestoreInstanceState()
where you would then extract the values from activity like this:Or from a fragment.
You would usually use this technique to store instance values for your application (selections, unsaved text, etc.).
Although the accepted answer is correct, there is a faster and easier method to save the Activity state on Android using a library called Icepick. Icepick is an annotation processor that takes care of all the boilerplate code used in saving and restoring state for you.
Doing something like this with Icepick:
Is the same as doing this:
Icepick will work with any object that saves its state with a
Bundle
.Not sure if my solution is frowned upon or not, but I use a bound service to persist ViewModel state. Whether you store it in memory in the service or persist and retrieve it from a SQLite database depends on your requirements. This is what services of any flavor do, they provide services such as maintaining application state and abstract common business logic.
Because of memory and processing constraints inherent on mobile devices, I treat Android views in a similar way to a web page. The page does not maintain state, it is purely a presentation layer component whose only purpose is to present application state and accept user input. Recent trends in web app architecture employ the use of the age-old Model, View, Controller (MVC) pattern, where the page is the View, domain data is the model, and the controller sits behind a web service. The same pattern can be employed in Android with the View being, well ... the View, the model is your domain data, and the Controller is implemented as an Android bound service. Whenever you want a view to interact with the controller, bind to it on start/resume and unbind on stop/pause.
This approach gives you the added bonus of enforcing the Separation of Concern design principle in that all of you application business logic can be moved into your service which reduces duplicated logic across multiple views and allows the view to enforce another important design principle, Single Responsibility.