Right now my activities behave as below:
But of course I'd like to maintain state as I navigate between activities so ideally it should behave like this:
What is the correct Android way to do that?
You can save the state by overriding the onPause() method of activity and reset it in the onResume() method. You can also use SharedPreferences to share state between activities. See SavingPersistentState.
Additionaly you can also go through the Activity Cycle.
Related
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)
How do I save temporary data on android?
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 or in-memory cache.
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.
I have activities like A->B->C->D. How can I close the A activity if I have 4 activities on my stack? Also later when I open activity E i want B to be closed aswell, so I want to have C->D->E only.
There is no such as a direct way to manage activities number in stack. So far I know that stack is big as much as available memory.
Also consider LaunchMode and whether activities are in the same task or not.
So, you might implement your own Activity manager to finish un-wanted activities.
Here is briefly how I see the solution:
Create a model to store activity, its index in stack, date ..i.e. ActivityItem
Create an empty List of ActivityItem in your custom Application. To avoid memory leak, use WeakReference. create a public setter adActivity to add and manage activities
Better approach to create activity base class and reuse it as superClass wherever you want to manage count of running activities. instead of repeating same implementation for each different activity.
OnCreate in your base Activity call adActivity and pass current activity.
adActivity job is firstly clean the list of destroyed activities. thanks WeakReference. Then manually kill older activities before last 3 items in your list. It's not easy as it looks.. for example: SingleInstance and rotation will make it challenge to achieve this :-)
that is it.
Good luck,'.
When you start activity use
startActivityForResult(intent,code);//different code for all activity
and call
finishActivity(code);//which activity do you want to close?
You can call:
finish();
after:
startActivity(intent);
In every activity that you want to close, when you open another activity.
I'm new to android development, and I have come across this article, that shows how to restore the activity state : http://developer.android.com/training/basics/activity-lifecycle/recreating.html
And I was wondering if it is the same about fragments, do I need to implement
onSaveInstanceState and onCreate
the way they show, or do I also need to add something to the activity, since it is a fragment, and it doesn't work exactly like an activity.
My app shows some content (video,pdf,img, etc ) and within every content I can start another content. What I want is to have only "one back history".
For example, if my activity history is like this:
VideoActivityIns1->PdfActivityIns1->VideoActivityIns2
I need to go back from VideoActivityIns2 to PdfActivityIns1, but one step back is should be MainActivity of my app.
How can I do this? Any help would be appreciated
Each activity has activity lifecycle methods you can override to achieve the result you need. Thus, you can either launch Activity2 onResume() on Activity1 onPause(),
http://developer.android.com/training/basics/activity-lifecycle/index.html
or, invoke ActivityManager to detect and manage the other activities.
http://developer.android.com/reference/android/app/ActivityManager.html
You can also make use of intent resolution mechanism to assign several priorities to your activities and then setup intent filters in each activity so you can start activities with a given priority in your code. You can do this either in Java or XML (though I suggest Java). Have a look at the Intent class.
I am working on an android application project which has more than 8 activities just up to now. I need to learn how back button behave in android. Because I need to override it and do some actions when it pressed. When back button pressed android looks up the trace file and go to the activity which you came from to the current activity. However in my application you can go to an activity from several other activities. And I should know from where i came to this activity so that i can decide whether I should override onBackPressedmethod or not. But I don't want to do this with carrying some parameters with something like putExtra and startActivity. Is there a better way to handle this problem? Thanks
Sure override onbackpressed and use intent to traverse to what ever class you want to move.
You could try doing a BaseActivity and putting your custom logic there.
All of your 8 activities would extend that BaseActivity that has custom behavior there.
From that BaseActivity you can do whatever logic you want in onBackPressed based on a custom variable that you would send.
I wouldn't recommend overriding onBackPressed ever. Check the other lifecycle methods: onPause or onDestroy.
If you want to do something like a custom navigation you should check the ActionBar goUp instead.
You can find out which activity launch this activity by calling getCallingActivity ()