问题描述:

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().

  • Will this work at all?
  • Can I just do onSaveInstanceState(new Bundle()), or do I have to initialize the new bundle somehow?
  • Will Android store the bundle and pass it to onCreate() for the next instance of the Activity it creates, or do I have to take care myself of storing the Bundle and passing it to the new instance (if so, how)?

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.)

网友答案:

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.

网友答案:

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);
}
相关阅读:
Top