I'm writing a simple app with 4 activities. I'll describe it quickly so you understand what I'm trying to achieve.
First activity - MainActivity has some TextEdit fields that collect 2 input parameters - number of reps and length of pause in seconds. A button takes me to the second activity:
WorkActivity - all this does is it starts counting until I press 'done' then it either calls PauseActivity, or if it has been the last rep, calls OverviewActivity.
PauseActivity counts down the seconds until next rep, then beeps at me to let me know it's time, and shows WorkActivity again.
OverviewActivity shows total workout time and times for each rep.
It also features a button that should just end the app. I know exiting your apps is not really in line with the Android application life cycle philosophy, but I need it (or something like it to happen).
I have a singleton controller class that keeps track of the reps and logs the time. I can kill this instance (or fake its death, so a new one will be created), but when I "close" the app and then click it again, I get the OverviewActivity instead of the expected MainActivity.
I expected that calling System.exit(0) would take care of things, simply shut down the application, so it will have to initialize anew when run again. Instead the whole thing started acting really derpy. When I click the button that calls System.exit(0), instead of vanishing my app sort of restarts. It shows the WorkActivity, and starts counting. When I click the done button (which should take me to PauseActivity) I get an exception. The application crashes - and then restarts again. This will repeat until I hit the homescreen button, and the app remains in this useless state until I kill it in application manager.
Also, I'm not exactly sure, but I think the System.exit(0) call (or the subsequent crash) disconnects the debugger, cause I've been unable to get Eclipse to hit any breakpoints afterwards. This means I can't really see the actual exception that occurs.
Can someone shed some light on this? Is there a way to use System.exit(0) correctly?
In the absence of this option, what would be the correct way of handling this?
I need the app to:
- when I click the final 'Done' button the Home button or the Back button, dispose of the Controller, (and everything else if possible), stop counting (if any timer is running) and essentially shut itself down)
- when I click the app's icon again, to show me a new instance (or one that appears new) with the MainActivity to greet me and all other activities in their default state.
Using System.exit(0) is a bad practice.
Calling exit() in this case would terminate the process, killing your
other component and potentially corrupting your data. The OS could
care less of course, but your users might not appreciate it.
Killing voluntarily your process will not help other applications, if
they have exhausted their internal Dalvik heap limit. No matter how
much physical memory a device has, the OS has a limit on how much
memory Dalvik is allowed to use in any process for heap allocations.
Thus, it is possible that the system has free half of its memory and a
particular application still hits OOM.
Do not use System.exit(0); instead you can just use finish().
Intent intent = new Intent(this, Activity2.class);
startActivity(intent);
finish();
Related
Please note the following vocabulary to avoid confusion
1) When I say reinstantiating an activity, I mean Activity.onCreate(bundle)
2) When I say starting from scratch an activity, I mean Activity.onCreate(null)
(Although I am not sure it makes a difference) For the purposes of this post, please assume that the Android applications I am interested in all have their activities launched in the same task
How does Android go about freeing memory from apps?
Lets say I have a phone. I am using many applications at once. I got bored of the current Snapchat application. So I press the home button and open Facebook. Note that I did not press the back button, and so Snapchat lives on in the recent apps overview.
Suddenly for some reason the phone is very low on memory and needs to start forcefully freeing up some from background apps.
Will the Android OS kill some activities of Snapchat in order to free memory
Will the Android OS kill all activities of Snapchat in order to free memory
How does Android go about managing "killed" apps?
Now lets say I want to go back to Snapchat. I hit the overview button and select Snapchat from the scrolling list of recently used apps.
Will the Android OS reinstantiate some activities of Snapchat
Will the Android OS reinstantiate all activities of Snapchat
Will the Android OS reinstantiate zero activities of Snapchat and just starting from scratch with the initial launcher activity.
TL;DRD: all activities are killed.
The ActivityManagerService doesn't seem to kill anything anymore (it just forces GC calls and dispatches trim events).
if (false) {
// For now we won't do this; our memory trimming seems
// to be good enough at this point that destroying
// activities causes more harm than good.
if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
&& app != mHomeProcess && app != mPreviousProcess) {
// Need to do this on its own message because the stack may not
// be in a consistent state at this point.
// For these apps we will also finish their activities
// to help them free memory.
mStackSupervisor.scheduleDestroyAllActivities(app, "trim");
}
}
Though when (if) it did try to kill something it would kill the whole process of a background app (it would simply call kill -9 [PID]). And since by default all your activities are run under one PID they all get destroyed when a process dies.
The same goes to the OOM and Low Memory Killers - the two operate with processes and make no distinction between your activities.
Please note, however, that some people claim that Android sometimes kills particular activities one by one on low memory. I failed to find any evidence of that in AOSP.
==============
Now, about restoring your app. I might not be an expert here cause this is connected to the Android's "Tasks and Back Stack System" which is way trickier than their tutorial videos make it seem.
The operation starts with calling ActivityManager#moveTaskToFront(...) and it eventually leads us to ActivityManagerService#moveTaskToFrontLocked(...)
There the OS will try to retrieve the stored task record associated with your app. If your app's been destroyed, the manager will have to go to ActivityStackSupervisor#restoreRecentTaskLocked(...) and if all goes well it's gona find the task and the back stack and do this for every activity in the task:
final ArrayList<ActivityRecord> activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
mWindowManager.addAppToken(0, r.appToken, task.taskId, stack.mStackId,
r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
r.userId, r.info.configChanges, task.voiceSession != null,
r.mLaunchTaskBehind);
}
The same method (WindowManager#addAppToken(...)) is called when you start a new activity and it goes with a comment:
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
So my guess is that when the OS restores an app it recreates the activity stack fully but only the topmost activity actually actually gets restarted. I guess, it's easy to set up an experiment to find out if I'm right here.
=======
One more update :) Yep, these two methods (ActivityStackSupervisor#resumeTopActivitiesLocked() and ActivityStackSupervisor#resumeTopActivityLocked(...)) are called a bit later. Though I really don't undesratnd why they resume activities in more than one stack - as I said, I'm definitely not an expert here.
I'was wondering a simple thing. I'm making an android app and I started asking my self about memory usage.
What does the android OS make when I call a new intent??
Imagine i have an intent with only one button and this button onclickmethod is making a new intent of the same activity.
If on click I do this??
Intent activityN = new Intent(Activity.this,Activity.class);
startActivity(activityN);
is the firstActivity killed or does android keep it?
And if I click 50 times??
thanks for your answers
Activities life cycle is a tricky topic.
In most cases the activity will be kept in memory, but in some cases Android may decide to destroy it to reclaim resources. You have no control over this behaviour, which may change between OS versions and even hardware configurations. Don't try to fight it - embrace it.
Activity state is saved in onSaveInstanceState(Bundle), which is called before placing the activity in a background state.
When the Activity is about to be shown - but was destroyed to reclaim resources - it can be recreated using savedInstanceState in onCreate() method. You are expected to handle this situation. Most programmers don't care, which leads to strange errors on screen rotations and after longer periods of inactivity.
You may think about this mechanism as a serialization/deserialization scheme, that allows Android to optimize memory usage, discarding the data that can be recreated on demand (such as UI layout) and saving only things that cannot be recreated, such as UI state (entered text, checbox states, etc).
Since Activity destruction is rather unpredictable under normal conditions, Android provides special developer's option to always destroy activities when possible. This allows you to properly handle all corner cases around activity life cycle without too much effort. Explore your device's developer options.
You may want to check out those articles to learn more about the topic:
http://developer.android.com/training/basics/activity-lifecycle/index.html
http://developer.android.com/training/basics/activity-lifecycle/recreating.html
Going back to your question about clicking the button 50 times... it will probably create 50 instances of activity, stacked on top of each other. It may be the case that Android starts to destroy first activities to make room in memory for new ones. Let's say that the device have memory for only 49 activities. You start 49 - all are kept in memory. You start 50th one and the 1st is going to be destroyed. Her state is saved in Bundle, so when you press back 49 times, the first one will be re-created from this saved bundle.
That depends on the flags you are supplying with your Intent.
If no flags then every startActivity creates a new Activity.
However, there can be FLAG_ACTIVITY_CLEAR_TOP orFLAG_ACTIVITYY_SINGLE_TOP flags.
It's boring to repeat it all here, have a look at the docs:
http://developer.android.com/guide/components/tasks-and-back-stack.html
Android keeps the first Activity. That's why when the second Activity is finished you can return (with results even) to the same state. If you clicked the button 50 times, you'd start 50 new activities. YOu generally want to avoid that, so its a good idea to disable the button after the first press. Luckily your new activity should quickly start and cover up the button, so 50 is hard to do (although 2 or 3 isn't).
I know how Android works concerning killing not needed processes if the memory is needed by another app, bu I dont like the following behaviour of the App I develop at the moment:
I start my App, which has a lot of different screens/activities
After using it, i push the Home Button of my phone and switch to some other App.
(Lets say I did this while Activity C on Screen C was active).
My phone is a HTC One X, I checked, that there are always about 300MB of Memory available, when I run the Apps I usually need.
The Problem:
Even if I restart the App after a couple of days without using it, the App restarts with Activity C on screen C. In my opinion, after some days of not using the App, it should restart with the "Welcome Screen" i created.
As there are no Backgroundprocesses or ressources used (all these stuff is done by pushing buttons and has to be finished - so no automated backgroundprocesses are needed), I think, Android does not feel the need to kill it.
Does anybody know, how the "Android Best Practice" looks like for this or where I can read what behaviour the App should have in this case?
(... I am not looking for Code, but I dont know what way I should go to solve this)
Many Thanks for any help
I think you can easily do finish() the activity's on onPause() method.
Not sure whether this is a best practice. Awaiting other answers.
If I'm not mistaking, the following flag can help you when used by an Intent starting a new Activity: FLAG_ACTIVITY_NO_HISTORY. As the documentation says:
f set, the new activity is not kept in the history stack. As soon as the user navigates away from it, the activity is finished.
So if all your Activities, except of the welcome screen, are started using this flag, next time a user comes back to your app he arrives at the welcome screen. The drawback of this solution is that if a user receives a call while working with your application, he will also be transfered to welcome screen when the call is finished. Don't know if there is any other solution. Hope this helps.
When i am put my application to the background and again awake it means all the Global variables are cleared.This is not happening always but at rare case only.I guess that could be memory crash only.Why global values are cleared? how to recover from this?
This might be the way Android works. Just because you close your last activity in your application doesn't mean that your application is cleared from memory. If Android doesn't need the memory space taken up by your application it won't necessarily be killed right away by Android. Also the garbage collector has it's own life cycle which doesn't necessarily get triggered on each activity destroy.
You can try this: Start Angry Birds and start playing around, fire off some "crazy chickins". Press the home button in the middle of an ongoing game and start Angry Birds directly again. Notice how you end up on the very same level you just "home-ed" out from. Press the home button again and start another application (the browser is usually memory hungry). After some time start Angry Birds again and notice how you'll have to go through the entire start up sequence again (i.e. you don't necessarily end up in the middle of the game, on the level you previously left).
If you really, really need to maintain application state, regardless of GC run or no-run, you should probably use SharedPreferences or a SQLite database. You can read up more on these concepts here: http://developer.android.com/guide/topics/data/data-storage.html
I'm not sure whether I need to add an exit button to my app. Is there any point to doing this? And if on exiting one activity or service is not .finish() or closed properly could this cause a lot of damage?
You don't need to add en exit button. If you don't, your activity will just be kept in memory until the system reclaims it. It will not consume any cpu.
Of course, if you have any worker threads running you should stop them in onStop() or onPause(), depending on what your threads are doing.
Many applications add an exit button, for some reason. I guess the reason is that they don't trust themselves to write proper code or they don't trust the Android OS to clean up properly.
Not going through the correct finish procedures will not cause any damage to others than yourself.
Anyone who says you don't need an exit button is right but putting one in never hurts. Users like to see a way to exit to the application, it's not about bad programming, it's actually about proper programming, give the user an exit button and if they never use it great and if it's there even better.
You don't need an exit button in your app. This is how android works. The user is not given any way to actually exit the application.
When you call 'finish', the application stack is just pushed to the background. It still exists in the memory. Android itself decides when to close the application(i.e. remove its instance from the memory) and generally this is done when your application becomes the oldest application which was not used for the longest time.
No, you don't. Read up on the activity lifecycle at developer.android.com
On older versions of android you had to be careful not to accidentally leave a background service running and holding resources but that's been reworked.
Guys you're righteous, but there are some cases when Exit button may have a sense. Let's say you're keeping some application-wide global data in YourApplication class (child of Application), e.g. some sensitive data or so. When user closes final activity and it's destroyed Application won't be terminated. As read Android developer resource - developer should not rely on Application.onTerminate() method. You can easily check it - even in case when all activities closed Application still alive. Whenever Application instance alive it's relatively easy to get access to those object and collect data.
I have found 2 ways how to kill Application class instance:
null'ate all object references (which is hardly possible for large projects) then call garbage collection
call
android.os.Process.killProcess(android.os.Process.myPid());
So Exit button may have function to finish all activities, call garbage collection then call killProcess() - which will guarantee safe removing of global data stored in Application.
I agree with above post by barmaley.
Long story short, you don't need to exit your application if your concerns are related to the Android system itself. Don't worry, be happy. And that applies especially for lazy users (remember the old Symbian days).
However, if you have something in mind about your application itself, then please go ahead and do it. You can finish the activity, nullify and kill. Just be reasonable because, as always, common sense is going to be better than all the tutorials and references in the world.
Anyway, just my 2c.
From a technical perspective, no, you don't need to add a quit button for all the very good reasons listed here.
Unfortunately users aren't informed in this way and regularly drop review scores because they have to 'use a task killer' or 'force close' your app.
It is a regular request and criticism in reviews/feedback for my app. So it may be necessary to appease users.
I think an exit button can provide the user with assurance that your app is closed.
I know, that it still doesn't mean that the app is definitely closed, but if the user feels more in control with an exit button then I say it is a good idea.
When I first started coding for Android, I thought it was a good idea to manually exit my main activity. What I discovered is that closing the activity via stopSelf leads to corrupt instanceState data, which caused a lot of ANRs when the activity was opened again.
The Activity Lifecycle document is information directly from the Google framework engineers. Every word is for a reason.
Consider that garbage collection takes cpu. This may seem trivial, but in designing a framework for a mobile platform, wouldn't you try to cache as much in memory as possible in case it was needed again, as cpu time = battery, and loading from flash is expensive?
GCing an entire app is non-trivial. Especially when the activity might be used repeatedly. The design had to consider all possible use cases. Cacheing makes sense. The system is designed with this principle.
I would say that not following the Activity Lifecycle document is asking for problems.
Some apps alter the configuration of the device while running or consume lots of CPU or data. You may want to give users an option to Exit the app altogether.
There are proper usecases for an Exit button.
For example, an app i made also needs to manage WiFi networks: the device configuration is changed continuously. Terrific and all while app is in active use, in this case a user would expect the behavior to effectively stop after exiting the application.
So my application has an Exit button mainly to cleanup the WiFi configs it created. I could make a button Stop and Cleanup, but no user would understand. They just want to turn the app off, thus Exit.
App running: wifi managed by app.
App exited: diy/android wifi.
Right now, choosing Exit in my application does the cleanup followed by a finish(), but the application itself lingers in the background. Functionally ok but confusing users. I could make a toggle action named "wifi feature on/off" but that wont make things simpler.