Here's the scenario:
Start Activity A
Activity A starts service S
Service S runs in foreground mode and shows up a notification which when pressed takes the user to Activity B (which has launchMode="singleTop")
Activity B shows up
Press HOME
Go into DDMS and kill your application process to simulate that your app died (press red STOP button)
Android will say "Rescheduling crashed service in 5000ms" (sometimes longer)
Service S restarts and notification is shown.
Press the notification icon when the service restarts...
...at this time, Android will recover both Activities A and B due to the fact the process ended unexpectedly. But despite the fact Activity B is singleTop android will spawn it AGAIN because the user clicked on the notification. This results into having A -> B -> B on the activity stack. Pressing back will take you again onto the first recovered instance of Activity B.
Can someone from the Android team clarify what is happening behind the scenes and how to avoid this? What is the best way to simulate that Android killed the process due to low memory? Is pressing STOP from DDMS good enough or an edge case and this should never happen under normal circumstances?
What is the difference between 'Force Stop' from Settings --> Applications versus STOP from DDMS?
Thanks in advance!
This behavior should not change based on whether or not the process is killed. The activity manager first looks through the server-side stack to decide what to do, and once the stack has been adjusted appropriately it resumes whatever is now at the top of the stack.
Check your app to make sure it is not calling startActivity() when re-initializing or doing something else like that. Look in the log to see what activities are being started and the intents being used. Use "adb shell dumpsys activity" to see what the current activity stack looks like. Maybe you have cleared the task affinity, so the second activity B is being started in its own task (in which case singleTop would have no impact)?
Also it is really hard to help people if you don't include useful details about what you are doing. The relevant log statements at the different steps, the state of the activity stack shown by "adb shell dumpsys activity", etc.
I am not too sure about the detailed differences between STOP in DDMS and Force Stop, but I am pretty sure DDMS bypasses some internal Android functionality that Force Stop would perform since I do not remember Android ever reinitializing my activities when i did a Force Stop. If this is true, then I am suspecting that what you are seeing is the result of two different tasks started by Android: one for the old, killed activities and another for when the killed service restarts. You can test this theory by setting the flag to "singleTask" and checking if the same behaviour occurs. Hope this helps.
Having A -> B -> B is possible even while B is singleTop: for situation when B is launched as other task. In the case there are actually 2 stacks: A -> B and B
Related
I've noticed an issue when I pause my app, say by pressing home, and then bring up the list of recent apps (via the square button) to resume it.
If I resume it shortly after pausing it, it works fine. But if I leave it paused for too long, i.e. a few hours or overnight, then when I touch its window to resume it, it just posts a "failed to start..." toast and removes the app from the list.
I've searched around, but haven't found any info about what would cause this or how to start debugging it.
My theory would be that is has to do with the activity lifecycle. You can find it here:
https://developer.android.com/training/basics/activity-lifecycle/starting.html
When an app is paused, the onPause() function is called, and if the app is paused, and the system needs memory for another app that is running in the foreground, it will stop, or destroy the activity. When you go back into the app, it calls the onCreate() and onStart() functions
I don't know how your app is structured, but my guess is that when the activity is stopped, it is leaving behind some kind of code that needs to reference something that is no longer there, or destroying the referenced thing itself. Then, when onStart() is called, it checks for that thing that is no longer there and crashes.
The best way to fix this is to make sure that each step of the life cycle isn't referencing anything that could possibly be non existent at the time it is called.
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.
If the user leaves a task for a long time, the system clears the task of all activities except the root activity. When the user returns to the task again, only the root activity is restored. The system behaves this way, because, after an extended amount of time, users likely have abandoned what they were doing before and are returning to the task to begin something new.
You might look up into the Android documentation regarding Tasks and Back Stack and upon some information about Pausing and Resuming an activity. :)
You issue probably related to memory management on android. It looks like android kills you app to release memory so that it can be used by another app. I have an app with very complex layout (The app loads too many images). After some times, when I run the app from recent app list, it always run the app from start. Not from the last state where I left the app. Anywa, nothing to worry about. This is normal behaviour.
As of my concern this is your problem-
you are starting an activity.
then you press home button. and the activity goes to background.
when you start the app after 5 minutes the app starts from the paused activity. but when you start app after 5 hours the app starts from the beginning.
Solution-
This is happening because the activity is being killed in background by the android system.
the application can be killed by calling the ondestroy() method of the activity.
and when the app goes to background it is added to the application stack of the android system. when ever android needs more memory for any operation it takes memory from the last application in the application stack. it kills the last application and takes its memory.
this is the reason your app is being killed after long time. your app is at the last of the stack and android has killed your app to get memory.
you can find more explanation of the process here.
How to solve this problem
this can be solved by bringing your app to front of the stack periodically.
you can run a service from your activity in background so that is stays on top side of stack.
or save the last opened activity in a shared preference and go to this activity when the app starts.
I have an app, a single activity app with fragments in it.
The usual use case for this app is, that you start it and put the phone away and every now and then, you get back to the phone and insert some data... It's a logging app, you are doing something and insert your results into the app...
I have the problem, that every now and then, my activity get's destroyed and is recreated with an empty bundle... (Most of the time this is not the case, but every now and then this happens...). My app sometimes starts a service, even this service is killed in this case...
This means, that the system has killed my app, does it? How can I avoid this?
I need to keep the user data and the current top fragments... And they are saved to the bundle and everything works as long as their states and the data get saved...
Btw., my activity is always the TOP ACTIVITY, only that the screen turns off often... I just want to keep my activity alive as long as possible until the user leaves it with the back button... Or to save the state reliably
IMPORTANT NOTE
onSaveInstance does not always work (it's not part of the lifecycle and therefore not guaranteed to be called)... it only works most of the time... I need a way to that works always... If android kills my app...
don't keep your app in memory
You don't want to block Android from killing your app. What you want is to restore your app's state properly. Then the user will never notice the app has been destroyed and the user still gets the benefit of an app that was destroyed when not in use.
If you really want this use a wakelock. This will drain your users battery so I think twice before implementing this... Info at How do I prevent an Android device from going to sleep programmatically?
onSaveInstanceState explained
To do so check what information is needed in the bundle and persist that information with the onSaveInstanceState(bundle:Bundle) method so you can reuse it in onCreate(sameBundle:Bundle).
More information available from Google documentation at Save your Activity state and Restore your Activity State.
About Android Activity lifecycle
As stated by #prom85 in the comments below it's not guaranteed that the onSaveInstanceState method will be called because it's not part of the lifecycle. Workaround for this is using the onPause lifecycle hook to ensure your data is stored.
More information at Android: onSaveInstanceState not being called from activity
I had a similar problem, I arrived at this post while searching for a solution, you have to play with the manifest to achieve this and also understand what exactly activity is, in Android eco system,
In Android activity is a task which has a pre defined work.
I dig a lot in the documentation, I found that, we can configure activity in two ways,
Persistent
non persistent
if you mention for the activity in the manifest as
android:persistent="true"
and run the below use case
Start the APP
Press back or home button
you select the activity in the back stack again to bring it to front
Activity enters start -> pause -> stop - > resume , it does not get into onDestroy method.
if do not mention
android:persistent="true"
for the same use case
Activity enters start -> pause -> stop -> destroy, and if you select the activity from the back stack
Activity enters resume->create->start
If you want to run a service/task on activity start which keeps running when the app is in back stack, then you have to start that in the onCreate method, and kill them onDestroy by specifying your activity as persistent in manifest.
I hope my above solution might help others who arrive here for the same problem
I have got some programs, need help.
I switch my app(have activity) to background(eg:By Home-Key), and use other APP to kill it.
then check it by Using getRunningTasks() and getRunningAppProcesses(), but i can not understand the result : I can find the app's Activity(TopActivty/BaseActivity)in the RunningTasks, but not in RunningAppProcesses
My problems:
1、Home can i remove all Activity when the process been killed?
2、In this case, how can i restart my APP when click the app-icon?
Thanks
can i remove all Activity when the process been killed?
When your process goes away, your activities, services, threads, and all that go away as well.
However, the "task" remains. This is basically a description of the back stack for your app, and any apps launched from it that were launched into your task versus starting a fresh back stack in another task. This description includes things like your saved instance state (i.e., onSaveInstanceState() Bundle), the Intent that was used to start the activity, etc.
how can i restart my APP when click the app-icon?
If the user is returning to your app via the recent-tasks list, ideally you do not "restart" the app, but return the user to where the user left off.
The developer documentation covers various ways that you can control, somewhat, the behavior of the back stack and your app (or individual activities) as they come back into being when the user returns to one of your tasks.
I'm launching an activity (ActivityA) using the technique described here with FLAG_ACTIVITY_CLEAR_TOP|FLAG_ACTIVITY_SINGLE_TOP. This works if all of the activities on the back stack are still in memory. ActivityA is shown and if I tap back, the app exits.
If I use SetAlwaysFinish to make paused activities be immediately finished and repeat my test, then when I tap back in ActivityA, I'm taken to the previous activity. This shouldn't happen.
Am I testing realistic conditions when I use SetAlwaysFinish? If so, how do I configure and launch ActivityA so that the back stack is really cleared and my test works under both conditions.
Using "set always finish activities" does not simulate any realistic condition. It is supposed to be used as a debugging help, but since Android doesn't actually finish activities when it needs to recover resources (it actually kills the host process instead), it is little help in debugging or testing real world conditions.
We know that when the system runs out of resources, an activity in background serializes its state and gets killed by the OS. When we resume it, the OS recovers the activity state by savedInstanceState passed to onCreate method. Considering we are responsible for handling what is going to be serialized/recovered, I'd like to have my activity killed in order to test the code I created for recovering. How can I achieve that? Forcing the application to be killed through the applications menu doesn't help.
Rotate your device (or emulator). Android saves, destroys, and re-creates the activity in the new orientation.
Download a task manager that kills the process in a less destructive way than "Force stop" in "Manage applications" settings. Example: GO task manager.
The task manager will kill the app (and the debug) but somehow not the activity stack (don't know why).
When you'll relaunch the app again, onCreate will be invoked with the last saved bundle/state.
The disadvantage of this solution, compared to Darrell's, is that you cannot debug it.
The advantage of this solution, compared to Darrell's, is that it is more close to real life scenario.
You can kill it from Eclipse also.
Go to the Android view. YOu should see the list of processes in the Devices tab.
Click on your process and then click the little "STOP" button.
Instant death!
FYI you can also attach the debugger this way by clicking on the little green bug