I am new to Android Programming.
I want to understand how Activity Stack is maintained for a particular Android Application and how does it changes based on user navigation.
For example, if there are multiple activities then how Activity Stack behaves when user clicks on Back Button or Home Button or launches a new Activity?
I was trying to find a suitable post where I can get all the information, but I did not get any. Can somebody please suggest me some links/posts where I can learn this?
Thanks!
Edited:
Links/Posts that I came across so far:
onSaveInstanceState is not saving my values ( onCreate input Bundle is always null )
Saving Android Activity state using Save Instance State
Android: Launch mode 'single instance'
Do you mean activities and the back stack?
Here is a link:
http://developer.android.com/guide/components/tasks-and-back-stack.html
A task is a collection of activities that users interact with when performing a certain job. The activities are arranged in a stack (the back stack), in the order in which each activity is opened.
The device Home screen is the starting place for most tasks. When the user touches an icon in the application launcher (or a shortcut on the Home screen), that application's task comes to the foreground. If no task exists for the application (the application has not been used recently), then a new task is created and the "main" activity for that application opens as the root activity in the stack.
When the current activity starts another, the new activity is pushed on the top of the stack and takes focus. The previous activity remains in the stack, but is stopped. When an activity stops, the system retains the current state of its user interface. When the user presses the Back button, the current activity is popped from the top of the stack (the activity is destroyed) and the previous activity resumes (the previous state of its UI is restored). Activities in the stack are never rearranged, only pushed and popped from the stack—pushed onto the stack when started by the current activity and popped off when the user leaves it using the Back button. As such, the back stack operates as a "last in, first out" object structure. Figure 1 visualizes this behavior with a timeline showing the progress between activities along with the current back stack at each point in time.
Related
I know that in Android, if stuff is idle for a while, the operating system will devour things to free up memory.
So if I have a first Activity, and I invoke a second Activity by using an Intent, and then invoke a third Activity using yet another Intent, I can use the back button to go back to the previous Activities.
But let's say I stay on the third Activity, and let the phone idle for a while until the OS decides to devour my app for memory. If I open the app again, will I have lost the stack I have formed from my Intents? Will I still be in the third Activity with the ability to press Back and go to Activity 2, then Activity 1?
The OS will handle how long a particular Activity stays "active" in memory. However, the "stack" shouldn't change, regardless of whether an activity is "active" or not. This is where the Bundle comes in handy and the methods: "onSaveInstanceState()" and "onRestoreInstanceState()".
Implementing these methods properly is the difference of the activity reappearing on the screen in an empty state vs. with its previous state maintained.
Some documentation on Recreating an Activity
The backstack stays intact for the task in hand. It will always stay in task and whenever the user presses the back button, it will go through the back stack like popping the last item. However, not all the activities in the stack are in the foreground. Usually, only the last item put into the back stack (the top of the stack) is in the foreground and if there are multiple apps/tasks open this may not even be true. Here is a great diagram to show this.
Now, lets say a user opens a task with a couple of activities in its back stack. The top activity is in the foreground and is running normally, but to preserve memory the other activities were destroyed. So now when the user presses the back button, the task knows what activity was in the back stack and knows it is now destroyed. So, it will recreate it following the Activities lifecycle and any data that was in it will be lost. One way to preserve it (mentioned by original answer) is using the onSaveInstanceState() and onRestoreInstanceState(), which save things in a bundle that Android preserves for the user so data can be saved. All of this information can be found in the docs. To answer your question more clearly, yes you will be in the activity you think you would be in, but you can treat it as a new instance of that activity and to recover the data from before to display it in the same way, you should use bundle and implement the methods aforementioned.
This is pretty elaborate, so I'll try and be as clear as possible. Currently, my application needs to reload some data when it is launched. I am loading this data in the onCreate/onRestart methods of my main activity. However, I need to be careful to not reload the data if the user never leaves the current task.
For instance, if I need to start the in-built Contacts application from my main activity to select a contact, then my main activity will pause/stop while I am selecting a new contact. When I return to my main activity, onRestart will be called. In this case, because I have never left the Application's task, I do not want to reload the data. This means some check needs to be included here to determine if the user has come straight back from the Contacts app without ever leaving it.
Otherwise, if the user exits the Contacts app while it was open and re-launched the app from the launcher menu (or recent apps list, etc) - I want to close the Contacts app and reload the data when the Main activity's onRestart method is called.
Is there a way to do this without using any user-frightening permissions (e.g. GET_TASKS). I have been stuck on this problem for a long time now so any help would be GREATLY appreciated :)
Tyvm,
B. Campbell
I learned a lot from the Android docs:
Tasks and Back Stack
Navigation with Back and Up
Application Structure
Here is some highlight:
A task is a collection of activities that users interact with when
performing a certain job. The activities are arranged in a stack (the
"back stack"), in the order in which each activity is opened.
When the current activity starts another, the new activity is pushed
on the top of the stack and takes focus. The previous activity remains
in the stack, but is stopped. When an activity stops, the system
retains the current state of its user interface. When the user presses
the Back button, the current activity is popped from the top of the
stack (the activity is destroyed) and the previous activity resumes
(the previous state of its UI is restored). Activities in the stack
are never rearranged, only pushed and popped from the stack—pushed
onto the stack when started by the current activity and popped off
when the user leaves it using the Back button.
It means when your application pick up a contact, the activity stack in the task might be:
| Activity A in Contacts |
| Activity B in Your App |
| Activity C in other app|
When the user leaves a task by pressing the Home button, the current
activity is stopped and its task goes into the background. The system
retains the state of every activity in the task. If the user later
resumes the task by selecting the launcher icon that began the task,
the task comes to the foreground and resumes the activity at the top
of the stack.
Even if the user exits the Contacts app while it was open and re-launched the app from the launcher menu or recent app list, the activity stack is still like the one we see above. The only possibility that may make your acitity start from another task is another app(might be a launcher app) that start the main activity in a new task by startActivity flags, which is a rare case. In this rare case, you can simply check the uid of the app who start your activity by Binder.getCallinguid() to differentiate it.
EDIT based on comments:
You may check if activity was opened from history by FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY:
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0){
}else{
}
You can also look into:
android:excludeFromRecents if you don't want your app start from recent apps
android:finishOnTaskLaunch
android:stateNotNeeded
If the data you are loading related to the application life-cycle not to a specific activity, you can load it in application class, so it will not be reloaded again unless your application task is killed.
My application start foreground service witch keep connection to server. It's show notification with pendingIntent witch show MainActivity. When i (user) tap on application icon (on desktop or application list) it's show "task stack". I mean if was lunched MainActivity it shows it, if user go to activity B or C (or lunch some other activities) it shows it (i mean top activity from task stack). There is a problem - if user tap on notification he see again MainActivity (on the top of the stack) but i expect top of tack stack (activity B,C or other witch was lunched by user at the end).
Half solves when i set attribute for MainActivity "singleTask", now it's always root of task stack, BUT a'm loosing all activities (B, C and other wich user lunched). Solution like in Reuse Activity on Top of Stack simular, but i need only one activity at root.
Maybe my logic is wrong and i need some another way to resolve this problem. But i want to know how can i programmaticly show task stack (top activity) like application icon does?
The documentation Tasks and Back Stack describes how to handle navigation correctly.
In short, if users tap on your navigation and you take them to an Activity in your app, when they click Back they should up in your app's Activity hierarchy until they reach the Home screen. They should never go to the stack in another task. That is, if they're in your app in Activity C, and you send a notification which they click that takes them to Activity A, then clicking Back should take them to the parent of A, and not to C. If they want to go to C, they can use Recents.
On older platforms, Recents isn't available.
This is by design.
To construct the proper synthetic back stack, use TaskStackBuilder
I read the developers guide on android.com about Task and back stacks where it says:
Suppose, for example, that the current task (Task A) has three
activities in its stack—two under the current activity. The user
presses the HOME key, then starts a new application from the
application launcher. When the Home screen appears, Task A goes into
the background. When the new application starts, the system starts a
task for that application (Task B) with its own stack of activities.
After interacting with that application, the user returns Home again
and selects the application that originally started Task A. Now, Task
A comes to the foreground—all three activities in its stack are intact
and the activity at the top of the stack resumes.
It seems like every Task creates it own stack (back stack). Is my assumption is real or there's only one stack, usually a compiler has, like C?
The back stack can cross Task boundaries. When the launchmode for an activity is set to singleTask, the activity will be created in a new task.
Suppose activity B has launchmode=singleTask in the XML file. When activity A launches activity B, the latter will be in its own task. However, pressing the back key will bring the user back to activity A. So A and B are in the same back stack, but are in different tasks.
See the discussion of launchmode in the page http://developer.android.com/guide/topics/fundamentals/tasks-and-back-stack.html.
disclaimer: I have not verified if the documentation is correct.
I'd say that what they say is true! Every Task creates it own stack (back stack).
lets imagine this application like enclosed image. R stands for Root activity and A and B are other activities. A is for displaying of some list, B stands for displaying detail of some value. From R I can get by 4 buttons to 4 A activities. My question is, whether in this scenario is A activity initialized for each time or I would be using only one A activity among whole application. If user selects A in right top corner activity A, then displays detail B and then from detail B goes to another list (but based on A activity). Will he still got the same content from the first A or he can have "new" A activity with another list?
Here is the point - I will be having let's say hundred of activites. Lot of them are "forms" displaying some content, application will have about 50 variants of those forms. Can I make for each form one activity a reuse it again in my activity without having connections to past usage of this activity?
Use android:launchMode="singleInstance" in your manifest if you want a single instance of your activity class
By default activities start over entirely every time you open them with a call to startActivity(). If your activity starts a new activity, it will essentially be put on to an activity stack and is paused while the new activity starts. If the user presses the back button, the last activity on the stack will resume as it left off (though I don't think this is 100% guaranteed as Android will kill off tasks as it needs resources so I wouldn't assume it).
So if you have this chain here:
A->B->C->D
where each letter represents a new activity with absolutely no flags or changes.
If the user is at D and presses the back button, C will resume. D is popped from the stack. If the user decides to go to activity D again, a new D will start as if it didn't happen (assuming you didn't save any persistent variables). If the user presses back twice, the application will be at B where C and D are no gone.
You can manipulate this chain with various flags like singleInstance to keep its state, or noHistory to ensure it doesn't get put to the stack (meaning it will be skipped if the user presses back).
Very detailed description of the various attributes