Android task lifecycle and static data, is a task ever destroyed? - java

Android activities have a well defined lifecycle and they will be paused, stopped, and destroyed. That is very well documented. My question is about the task that contains my activities as described in the docs.
Under low memory or other conditions, will the task ever be shut down by the OS? (I understand the user can Force Stop the app).
Can I assume my Singletons and static data will always be available?
What about static members defined on an Activity? It appears that the Activity may be destroyed, but the static data lives as long as the task lives.
android.app.Application has callbacks like onLowMemory() and onTrimMemory() but these seem to be voluntary, meaning it is great if the app cooperates with the OS, but it doesn't have to. So, I'm pretty certain my task is never normally killed and singletons and statics are reliable. Is this correct?
This answer also had some good background.

I was extremely curious about your question and so I quickly did a simple check with a very simple project and I'll post what I found - I'll answer the rest based on hypotheses as Android's clean up process is quite arcane.
Created 3 activities - A, B, C. A can call B or C. A is the starting
point of the app. B and C cannot call anything. C has a static
integer member x.
x is a class member of C and initially does not have any value. I set
it to 5 and printed it out in the onCreate() of C. It is also printed
out in the onResume() of A.
When I started the app, a toast was displayed on A which said 0 (C.x
has not been set yet). Then I navigate to C. I get a toast c=5.
Then I press back and go back to A. I get a toast c=5. C has been
destroyed.
Then I go to B. No toast. Go back to A. I get a toast c=5.
From A, I press home. From home, I again reopen the activity. I get
c=5.
I press back to go back to home (destroying A). Then I reopen the
app. I get c=5.
Then I go back and force stop the app from settings. Then I reopen
the app - I get c=0. Force stop completely removes everything from this task.
From this, you can say that static values continue to exist even after the Activity has been destroyed. Even after an application is closed, the value is still retained by Android.
Can I assume my Singletons and static data will always be available?
I would say that you can assume this as long as Android is not pushed to the point where it decides that memory needs to be reclaimed.
From the Android tutorial book by Commonware, I understand that any task that is running in the background is considered as an important task and will not be shut down by Android. But if another task comes to the foreground, then this is given a higher priority and all tasks in the background assume lower priority. If Android decides the task in the foreground needs more memory, it will start killing processes based on order of priority which depends upon a number of factors. Under low memory conditions, any task can be killed. In extreme cases, the task on the foreground itself may be killed.
I hope this answers your question. It certainly piqued my interest.

Can I assume my Singletons and static data will always be available?
You can never assume that. Sometimes contex changes (when you go to the settings and turn gps on for instance) and then your apps is being recreated. OS can destroy your activity in any time. You should never operate on static data even on PC programs

It seems that the OS can kill your task in low memory and other situations. And, of course, your statics and singletons die with the task.
If you need your statics and singletons to survive task shutdown and restart, you need to persist them somewhere. Android Application Framework FAQ has good suggestions. I found that you can leverage onSaveInstanceState() and save your data as part of the save instance bundle. It will be restored when the Activity is restored. See Controlling Android Activity restart after a process stops

Related

What exactly happens with static variables and services when the MainActivity is destroyed by the Back-Button and then recreated?

I would like to understand better what exactly is Happening when the Back-button is pressed and the MainActivity is destroyed in Terms of static variables and registered services.
this is what i know already:
onDestroy() will be called.
the activity is still listed when you hit the overview-button (the same as if ou hit the home-button or switch to another activity). When you activate it again, onCreate() is called.
What I Need to know is:
1.) what happens with static variables which are declared and initialized globally.
i.e.
static boolean logging_on_flag = false;
this is turned to true when the app is running, but if the activity is detroyed by the back-button and then recreated, will it be true or false?
2.) What happens with registered Services (listeners)?
i.e., I use Location Services to log my Location data. After registrating the Location listener, the System calls the method onLocationChanged() every time the Location changes. In that method, i do the logging.
When i leave the app with the back-button, will this process be interrupted? will the listener be unregistrated?
I am confused and forced to ask the experts here, since the back-button-behaviour of my app changed since I started to work with Fragments.
Before:
leaving the app with the back-button did not Interrupt the logging process, but the non-static variables were reinstanciated when the activity was selected again. Since the listener was bound to the old variable instances, changing the new instances did not have any effect on the logging process anymore. Furthermore, the listener would be registrated again because this is Happening in onCreate(), which lead to dual logging (every measurement was logged twice).
I could solve this by making the logging_flag static (which prevented instanciating) and checking in onCreate() if the flag is already true and if this is the case, the listener was not registrated again. This worked like a charm, since the flag remained true after recreating.
After implementing Fragments here and there:
The behaviour on leaving the app by pressing the back-button seems to have changed completely. Now, the logging is stopped immediately as the back-button is pressed and when you get back to the app, it is completely restarted and even the static variable was not true anymore but false.
Can anybody explain me, why the behaviour has changed in Terms of the static variables and the services?
Please note that this is a General question to get a better understanding of the back-button. I am not asking for a solution (and yes, I know I should better work with savedInstanceState).
statics are not part of the object so they still alive until you assign null to them. Or kill application.
Answering your question:
1) static will contains last value
2) Listener will be working until you kill app. You must unregister listeners on close.
Why behavior change? It didn't change. I think you have made somewhere mistake, but can't tell without seeing code.
what happens with static variables which are declared and initialised
globally.
They live as long as your the app process is living. When you go back to the home screen of the system, the app process is not necessary killed (it's managed automatically by the system if it considers it has enough resources or not). So potentially your static variable can still have the value you've set, the next time you launch the app.
What happens with registered Services (listeners)?
Depending on how you've started the service, it can still run in the background even if you don't need it!. So don't forget to stop everything when the app is stopped.
Concerning the listeners, they will still be affected to the service so it can create memory leaks if you've forgotten to un-register them.
Conclusion
You should avoid to use static variable to store data (you can use final static as constants).
You should use onPause to stop services / unregister listeners... and onResume to restart them.

What are the Advantages and disadvantages of AsyncTask in Android framework?

I am learning Android app development from Udacity.com by Google engineers and they said,
"It is not a good idea to use 'AsyncTask' as it is not attached to an activity life cycle. The virtual machine will hold on to the activity object as long as the Asynctask is running, even after Android has called onDestroy( ) method for the activity and expect it to be discarded.
If you rotate your phone, the behavior is to destroy the current activity and instantiate a new one. The naive AsyncTask implementation now has two threads trying to do the same update. So it is not the best pattern for a potentially very long running background operation , such as fetching from web services. If you leave the app, the asyncTask will run as long as as the process is kept alive , but will run at a lower priority, and your process will be the first thing to be killed if the device needs more resources. "
1) If using AsyncTask is disadvantageous why was it created? What would have been the design philosophy or the cause to create it in spite of having services(or something similar to achieve same kind of functionality)?
2) What are the situations where Asynctask should be used for betterment compared to Services/similar options available in Android?
3) What are the situations/places Asynctask should never be used?
Please do not downvote this question. I searched Stackoverflow and I couldn't find a similar question.
Advantages of AsyncTask
Provides generic solution for all network calls
Publish progress to UI while executing.
Run Asynchronously
Easy to maintain and read.
Problems in AysncTask
When you rotate your screen, Activity gets destroyed, so AsyncTask will not have a valid reference to publish data from onPostExecute(). In order to retain it, you need to usesetRetainState(true) if calling from fragment or onConfigChanges() if calling from activity method of an activity.
If activity gets finished, AsyncTask execution will not cancelled automatically, you need to cancel them else they will keep on running in the background.
If any exception occurs while performing network task, you need to handle them manually.
Whereas AsycTask, Services, IntentService, Threads all run on different threads and all serve different purpose.
please read more detail here.
So you need to decide when to use which component while performing non UI operations.

Android AsyncTask/Service killed before task complete

Synopsis: I need a way to start a task and have it persist through onDestroy() of app until it completes, or ability to pick up where it left off.
In my app, I have a ListView containing some items from a database. Hopefully only about 10-30 items, but potentially thousands (if the user never clears it, although I have prompts to clear it from time to time).
I have set up an AsyncTask to perform clearing the selected items from the list when the user wants to. However, I've noticed that the AsyncTask is killed when onDestroy() is called, for example if the user selects all items to delete, presses delete, then swipes app out of Recents while task is still performing.
I remember learning somewhere that a Service persists longer than an AsyncTask, so when the task gets killed I hand off the data to delete to a Service that I created. It does this by
intent.putIntegerArrayListExtra(list);
and get data from it in the Service. The Service persists far longer than the AsyncTask (only about 4-6 seconds), but still not all the way to completion. I know a little about START_XXXX flags, but that would be bad practice for this task, since they'd either send the whole list back to itself, or never really stop.
What is the preferred method to delete selected items from a database without it stopping when the app is killed, or at least to pick up where it leaves off?
Thanks all!
Your problem is very much like this: You have an application open in your favorite OS which is doing things in the background and then in the middle of it, the user force closes it. Logically, it will stop everything it's doing and stop executing and there's not much you can do to interrupt it.
There's no ideal solution to stop this from happening so what most people end up doing is to warn users that stopping the app when this operation is in process can have unwanted consequences.
In Android however, you have another option which is slightly more robust: you can write a persistent background service what continues running even if your app isn't running, but that still wouldn't solve the problem of what happens if the user switches off the phone when you're deleting from the DB? which would be the next logical question given your context. (personally, I would not recommend this approach for your task).
Best you can do is to maybe write a shared preference for every row you've not yet deleted (this will be the full list of rows you want to delete when you start deleting). For every row (or bunch of rows) you delete, change this preference to remove those rows from the preference and then if the app is interrupted, when you restart your app, read this preference and continue where you left off.
Alternatively, do what others do and warn users (by use of dialogs for instance) that they shouldn't stop the app until the delete is done otherwise bad things happen, etc.
I would strongly discourage you from using a service simply because it lasts longer than an AsyncTask. That's way too hacky and not at all reliable.

How disable destroy my activity

My app contains Activity. I start it by Intent. Than I turn my Activity to background (switch to Home Screen or similar). After some time the OS destroy my Activity (I think when memory is low). It is possible protect my Activity (in background) from destroy by OS? Or increase it priority to maximum?
Activity is made for a UI holding elements. Service is made for background tasks. From this already sounds logic to make a Service instead of try to keep Activity in background.
Also there are BroadcastReceivers, which will be called on different actions. Boot completed, Internet lost, got and so on.
I think you know what do you want to archive, I would suggest telling in detail an will get a lot better response, with enumeration, maybe code part of component needed to use.
Keeping Activity forced alive is a bad idea in general.
You can load WebView in background.

WeakReference/AsyncTask pattern in android

I have a question regarding this simple frequently occurring situation in android .
We have a main activity , we invoke an AsyncTask alongwith the reference of the mainactivity , so that that the AsyncTask can update the views on the MainActivity.
I will break down the event into steps
MainActivity creates an AyncTask , passes its reference to it .
AysncTask , starts it's work , downloading ten files for example
The user changed the orientation of the device. This results in an orphan pointer in the AsyncTask
When the AsyncTask completes , and tries to access the activity to update the status , it crashes , because of the null pointer .
The solution for the above is to keep a WeakReference in the AsyncTask as recommended by the book "Pro Android 4"
WeakReference<Activity> weakActivity;
in method onPostExecute
Activity activity = weakActivity.get();
if (activity != null) {
// do your stuff with activity here
}
How does this resolve the situation ?
My question it , if my asynctask is downloading ten files , and upon completion of 5 the activity is restarted (because of an orientation change) then would my FileDownloadingTask be invoked once again ?.
What would happen to the previous AsyncTask that was initially invoked ?
Thank you , and I apologize for the length of the question .
How does this resolve the situation ?
The WeakReference allows the Activity to be garbage collected, so you don't have a memory leak.
A null reference means that the AsyncTask cannot blindly try to update a user-interface that is no longer attached, which would throw exceptions (e.g. view not attached to window manager). Of course you have to check for null to avoid NPE.
if my asynctask is downloading ten files , and upon completion of 5 the activity is restarted (because of an orientation change) then would my FileDownloadingTask be invoked once again ?.
Depends on your implementation, but probably yes - if you don't deliberately do something to make a repeat download unnecessary, such as caching the results somewhere.
What would happen to the previous AsyncTask that was initially invoked ?
In earlier versions of Android it would run to completion, downloading all of the files only to throw them away (or perhaps cache them, depending on your implementation).
In newer Android's I am suspicious that AsyncTask's are being killed along with the Activity that started them, but my basis for suspicion is only that the memory-leak demo's for RoboSpice (see below) do not actually leak on my JellyBean devices.
If I may offer some advice: AsyncTask is not suitable for performing potentially long running tasks such as networking.
IntentService is a better (and still relatively simple) approach, if a single worker thread is acceptable to you. Use a (local) Service if you want control over the thread-pool - and be careful not to do work on the main thread!
RoboSpice seems good if you are looking for a way to reliably perform networking in the background (disclaimer: I have not tried it; I am not affiliated). There is a RoboSpice Motivations demo app in the play store which explains why you should use it by demo-ing all the things that can go wrong with AsyncTask - including the WeakReference workaround.
See also this thread: Is AsyncTask really conceptually flawed or am I just missing something?
Update:
I created a github project with an example of downloading using IntentService for another SO question (How to fix android.os.NetworkOnMainThreadException?), but it is also relevant here, I think. It has the added advantage that, by returning the result via onActivityResult, a download that is in flight when you rotate the device will deliver to the restarted Activity.
The WeakReference class basically just prevents the JRE to increase the reference counter for the given instance.
I won't go into Java's memory management and answer your question directly: The WeakReference resolves the situation by providing the AsyncTask a way to learn if its parent activity is still valid.
The orientation change itself will not automatically restart the AsyncTask. You have to code the desired behavior with the known mechanisms (onCreate/onDestroy, onSave/RestoreInstanceState).
Concerning the original AsyncTask, I'm not 100 % sure which of these options will happen:
Either Java stops the thread and disposes the AsyncTask, because the only object holding a reference to it (the original Activity) is destroyed
Or some internal Java object maintains a reference to the AsyncTask object, blocking its garbage collection, effectively leaving the AsyncTask to finish in the background
Either way, it would be good practice to abort/pause and restart/resume the AsyncTask manually (or handing it over to the new Activity), or use a Service instead.
How does this resolve the situation ?
It doesn't.
The referent of a WeakReference is set to null when the garbage collector determines that the referent is weakly reachable. This does not happen when an activity is paused, and does not necessarily happen immediately when the activity is destroyed and the framework discards all references to it. If the GC has not run, it is entirely possible for the AsyncTask to complete while its WeakReference still contains a reference to a dead activity.
Not only that, but this approach does nothing to prevent the AsyncTask from uselessly consuming CPU.
A better approach is to have the Activity maintain a strong reference to the AsyncTask and cancel(...) it in the appropriate teardown lifecycle method. The AsyncTask should monitor isCancelled() and stop working if it is no longer needed.
If you want an AsyncTask to survive across configuration changes (but not other forms of activity destruction) you can host it in a retained fragment.

Categories

Resources