user149408
user149408

Reputation: 5881

Save and restore instance state of an Activity manually

I have a download activity in my app, where users can download some content. The activity is called from the main activity, and retrieves the list of available files to download over the network.

To avoid fetching the whole list again when the download activity is recreated e.g. because of rotation, I override onSaveInstanceState() to store the list in a Bundle and evaluate the Bundle passed to the onCreate() method. That works well for rotation.

However, I would like to be able to implement the same behavior if the user hits Back and later returns to the download activity. Android in this case does not call onSaveInstanceState(), hence nothing gets saved.

My idea was to override onBackPressed() and include a call to onSaveInstanceState().

UPDATE:

Simply adding

@Override
public void onBackPressed() {
    onSaveInstanceState(new Bundle());
    super.onBackPressed();
}

gives me the following exception:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

for the call to onBackPressed(). (Swapping the two lines does nothing, presumably because there is nothing left to save.)

Upvotes: 4

Views: 1362

Answers (2)

user149408
user149408

Reputation: 5881

I finally came up with the solution described below.

A word on usage: this will keep the state of the download activity in main memory, where it will occupy space. Also, Android may kill a background app at any time, typically if it runs low on memory. If that happens, the state information will be lost.

For my particular use case I decided I could live with these limitations: the state information written by my app is in the kilobyte range, and if the state information is lost, it can be recreated (it just takes time to fetch the list from the server). YMMV.

In the onStop() method of the download activity, do:

Bundle outState = new Bundle();
this.onSaveInstanceState(outState);

Store outState in a place where it can be retrieved when needed. In my case, the BroadcastReceiver which processes the download manager events was the place to put it.

To bring up the Activity from the BroadcastReceiver, do the following:

Intent downloadIntent = new Intent(context, DownloadActivity.class);
downloadIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
downloadIntent.putExtra("savedInstanceState", savedInstanceState);
context.startActivity(downloadIntent);

In the onCreate() method of the download activity, do:

@Override
protected void onCreate(Bundle savedInstanceState) {
    Bundle state = savedInstanceState;
    if (state == null)
        state = this.getIntent().getBundleExtra(Const.KEY_SAVED_INSTANCE_STATE);
    super.onCreate(state);
}

Upvotes: 1

CommonsWare
CommonsWare

Reputation: 1006869

Will this work at all?

No.

Will Android store the bundle and pass it to onCreate() for the next instance of the Activity it creates

No.

do I have to take care myself of storing the Bundle and passing it to the new instance (if so, how)?

No.

Store your model data in a file or database, with a process-level cache (e.g., a custom singleton) to minimize disk I/O. Load your data out of the cache where available, or reload it from disk if needed.

Upvotes: 3

Related Questions