How can I save activity state (B) when moving to previous activity (A) and how to restore it's previous state when moving back (to activity B)?
SCENARIO
Content of activity B can be changed by user. After finishing work, performed changes can be persisted (e. g. saved to local DB). Before persisting, user may want to navigate back to previous activity. At this point, "work session" should be somehow saved temporary in memory. After returning back to activity B "work session" should be restored, so user can continue in work.
APPROACHES
Standard methods onCreate(Bundle)
and onSaveInstanceState(Bundle)
are used to restore/save activity state when device configuration changes (e. g. on rotate). As onSaveInstanceState(Bundle) is not part of activity's life-cycle, this method does not get called on "back-press" when activity is destroyed (by default finish()
is called). The same applies for onRestoreInstanceState(Bundle). Obviously these methods alone are not sufficient to restore activity state after lefting an activity.
Transfering bundle state between activities
One way I can think of is to override onBackPressed()
in such way it will start an Intent
to previous activity A with bundle state Intent#putExtras(Bundle)
of current activity B. When moving back, starting an Intent
to activity B, this bundle state will be delivered back Intent#putExtras(Bundle)
to restore the state of activity B. However this also require to override onCreate(Bundle)
and onSaveInstanceState(Bundle)
in A so bundle state of B would not be lost on configuration change before navigating back to B.
Not finishing an activity on back-press + non-default launchMode
Another way (more cleaner) is to override onBackPressed()
so that it would start Intent
to previous activity A without calling finish()
of current activity B so activity B will hang in memory in paused state (waiting for resume). To resume activity B, manifest configuration android:launchMode="singleInstance"
is required so android will use existing activity (paused B) instead of creating new one (B2) when navigating back to activity B (startIntent(B.class)
).
Details: launchMode singleInstance creates singleton activity in new task (task = set of activities with the same group id i. e. affinity, normally app activities have the same affinity i. e. app = single task).
Drawback: transition animations does not work with singleInstance mode. It seems that singleInstance task may not be fully initialized at animation time. For more details: Custom animation doesnt work on SingleInstance Activity.
Saving activity state to SharedPreferences
Saving activity state to SharedPreferences
on "back-press", restoring activity state from preferences in onCreate(Bundle)
like in following link Save activity state to SharedPreferences.
Drawback: unable to save Bundle
state (only primitives: putInt
, putString
, ...).
Others
Some of the methods listed in Share data between activities can be used. Answers from this link refers to developer.android.com/guide/appendix/faq/framework.html which is unfortunately broken. Here is an alternative source http://wing-linux.sourceforge.net/guide/appendix/faq/framework.html.
About sharing data via Application object:
- Don't Store Data in the
Application
Object, - Using the Android Application class to temporary persist data.
Based on Application class documentation, using static singletons over
Application
is more preferable.Base class for maintaining global application state. ...
Note: There is normally no need to subclass Application. In most situations, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), include Context.getApplicationContext() as a Context argument when invoking your singleton's getInstance() method.
It seems that putting data in Application
object or static singleton is so far the best solution for this problem.
QUESTION
Is there any build-in solution for this (without need of overriding onBackPressed()
)? For example saving activity on back-stack with it's state. If not, what is the common pattern to save activity state in such situation?
RELATED POSTS (just to link them with this post)
When you back out of an activity, the activity is not just destroyed programmatically, but also conceptually. In other words, the user expects it to be gone. We talk about saving activity state in situations where the activity object is destroyed but the user perceives that it still exists, such as during configuration changes or when it's in the background or backstack.
What you're trying to save is properly thought of as application state, not activity state. As such,
SharedPreferences
is an appropriate place for it. Whether it's the best solution is a matter of opinion and depends on your use case.For an alternative way to handle this, you can map your view's states to a data structure and save it as an object notation (such as json) to your local and when your activity is created / re-created you can read your state from local and bind them with your views.
For more information and example, you can check
Spotify's
presentations and open source project which contains information about how they manage application's ui from apis. (I know it's not exactly what you're trying to do but you may find some tricks.)If you need to save your data in your activities, you can use
Local Db
orin-memory cache
.