I got some concerns about AsyncTask that I could not clarify when reading the documentation.
My app main Activity runs several AsyncTask's when it's created. These AsyncTask's mostly download data or retrieve data from the DB.
If I go to a different Activity, will the AsyncTask's created on
this one continue executing? Or will they stop working and leave the
task half done? If so, will they go on somehow when getting back to
this activity?
In order to start one of the activities from the
one that is running the AsyncTask's, I need one of the AsyncTask's
to be fully executed. How do I set this constraint? Could you show
me some sample code of this, please?
Thanks
If I go to a different Activity, will the AsyncTask's created on this one continue executing? Or will they stop working and leave the task half done? If so, will they go on somehow when getting back to this activity?
Yes, it will continue to run. This can be a bit of a double-edged sword as it will typically also hold on to the Activity instance, causing it to live beyond its onDestroy() callback, which is not ideal. If the task you are running does not have the same lifecycle needs as the Activity itself, it may be better placed into a Service.
In order to start one of the activities from the one that is running the AsyncTask's, I need one of the AsyncTask's to be fully executed. How do I set this constraint? Could you show me some sample code of this, please?
There are way too many ways to do this, many depending on the architecture of your application, to provide specific sample code...but here are a few higher level ideas. Since AsyncTask provides a simple callback method on the main thread (onPostExecute) when the task execution is complete, you can set a flag at that point. Or perhaps simply check for the existence of whatever data the AsyncTask is retrieving from any code where the Activity would be launched. Again, a Service would provide good context for this, as multiple Activities could connect to the service and check the task status before moving forward.
Another option, depending on your application, is to have the result of the task dumped into a ContentProvider. ContentProviders include a nice interface for notifying observers of changes without resorting to global Broadcast Intents.
HTH
Ive done something similar to this before using Intents and Broadcast Receivers.
If you get the Async tasks to send a global or app-wide intent when they are finished, its easy enough to have a receiver pick it up if you construct them properly. By having a receiver created when you push a new activity onto the stack, and have the receiver close when an activity is paused, there will always be a receiver out there to grab the intent and be told that the (example: data is downloaded from the db) and act on that.
If you try and start an activity that requires that data, you can either deny the creation of that activity if the intent hasn't been found yet, or create the activity and have it put up a progress bar or something while the data finishes downloading, then have its receiver act on the intent when it arrives.
Hope this helps.
Related
In the android project that I have, all activities have some simple computations, but, the computations are not dependent on any activity. They depend on various sensor values. For some values of the sensors, a new activity is started. For the computations in the new activity, values from the previous activity are also required. I can pass the data in the intent, but in the transition time between starting the new activity, I miss some sensor values.
So as a workaround, I start a service that performs the computation. All the activities implement the method to start a new activity. Then the activity binds to the service and the service calls the method to start a new activity based on the sensor values. This seems to work fine and help with the data not being lost.
However, I am not sure that is this a good practice? And is there a simpler way to do this?
I like your thinking of handling the launches of each activity from a service based on sensor values. However, from the perspective of Android, this is open to severe memory leaking issues.
If I have understood correctly, you are launching an activity based on the values retained by the service, which is completely fine. However, can you think of any possibility in which you are doing a network call or any other asynchronous work in your activity which is launched? Then what about the background service launches another activity in the middle of that asynchronous call and then launches the new activity? The asynchronous call will return with some values to be provided to the calling activity which is out of context right? This will cause a memory leak and hence it may crash your application in some places.
I would like to suggest to maintain a queue for these activity switching operations in which you can handle the activity switching in more sophisticated ways. Just wait for an ongoing asynchronous call to be finished and return with some values to the calling activity and then launch the next activity. Whenever a data comes from your sensor, push the command for launching the new activity in a queue and then launch the new activity instantly if there is no current asynchronous call is running.
Hope that helps!
Update
so any guides to implement the queue suggestion?
You might consider having a basic queue implementation here. The queue will have the information of the next action to be performed and you will have another flag which will indicate if the action to be performed is safe to perform now.
if I wait for the asynchronous call to return, would I be blocking the
UI?
It depends on your implementation. I am not quite sure what you are talking about as I am not very aware of the overall application design of yours.
However, I think you need to look into RxJava which enables Android to work on an event-driven mechanism.
Here is problem which I'm trying to solve for three days:
For example, REST client app perfoms a lot of background work (network calls) and posts result back to UI thread. It is obvious that it should be done asynchronously. Android allows to do this in several ways (for example AsyncTasks and IntentServices).
The biggest problem of running asynchronous tasks from activity is configuration change.
For example we have activity which starts download process in AsyncTask and shows ProgressDialog. After screen rotation, activity is being recreated by OS. As the result when asynctask will try to dismiss progressdialog of old (dead) activity, it will fail.
There are several solutions to this problem:
first one is to retain asynctask in worker fragment: Great post how to do that is here. Big advantage of this solution is that OS knows when to call onPostExecute() method. In some cases onPostExecute() maybe called in moment when old activity is destroyed and new one is still not created. But that doesn't happen because OS doesn't allow execution of onPostExecute() before onAttach() is called. Disadvantage is that AsyncTasks are not suitable for long term operations and behaves differently depending on OS version.
the second approach is using LocalBroadcastManager and IntentService. Here is another post which shows how to use it. What will happen if service will send message to BroadcastReceiver when it is unregistered (the moment when activity is being recreated)?
the third solution is dirty hack: declare this in mainfest android:configChanges="keyboardHidden|orientation". Is not appropriate for me.
Maybe someone knows another solution?
You can prevent screen orientations before the task with setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) and restore it after.
The othet other idea is a service. You're worried that when one orientation is closed and before the other is loaded you may miss a broadcast. In that case the service should store the data somewhere the fresh activity can load it. (SqlLite, a file, sharedPrefs)
Also note broadcastRecievers can be registered in the manifest. So always on, so to speak.
I have an activity in which I do server sync with a back end server using a subclass of asyctask.
Given it is a network task and might take couple of seconds. I am afraid of the following scenario to take place.
The activity starts, and whenever the asynctask should start to run, it does so.
The onPrexecute() is called, executed, and over. Than the doInBackground() is called, and is done so, however, just when the method is being executed, the user presses the home button and swipes the app from the RECENT APPS. (this ofcourse causes the app to terminate and all the onDestroy methods get called of the alive activities..(Correct me if I'm wrong on this one)).
In my onPostExecute() method, I am inserting the data to DB and updating the VIEWs.
But since the app is 'terminated' the onPostExecute() method never runs.
my questions are :
When the user presses the home button and gets out of the app and swipes the app, is doInBackground halted at that moment ? that is, it is cut in the middle and does not continue what it does ?
What happens to the data that I was going to get from the server and put inside the DB ? Is it advisable to do put the data in the db inside the doInBackground ?
AsyncTask is a background task it will continue to run even if the app is closed and onDestroy() is called. The problem would be when the task enters onPostExecute() and tries to update any views associated with the activity it is bound to, as that activity no longer exists. If you're concerned about this, one thing I've done is to keep a reference to that AsyncTask in the calling activity, and then call the method myAsyncTaskReference.cancel(true) to cancel it in the onDestroy() of the calling activity.
Yes, I would put the DB operations in the doInBackground() method, as that runs in the background on a separate thread, and doesn't require a reference to the app activity.
Have you considered using a service for this type of thing instead? I would strongly recommend an IntentService, which is a subclass of service which is specifically designed to perform a single task in the background (similar to AsyncTask), and then kill itself once completed. It's quite easy to implement and usually only involves overriding one method - onHandleIntent() - which is called when the service starts.
It can handle all your DB operations and it has no reference to an activity and so the problem you're worried about in #1 would never occur. If you need to update a view, you can have your IntentService generate a broadcast once it's completed, and your Activity can register for that broadcast and update it's views accordingly when it receives it. And if your activity is no longer around once the broadcast is sent then it doesn't matter and nothing will fail.
When user presses 'Home', your Activtiy will pause but doInBackground will NOT, but may or may not terminate by system when system feels like it. Activity's onPause will be called. Your Asynctask doInBackGround will NOT halt. It will continue to run until the system kills your App process.
Yes, Db operations can take long. Its advisable to put in doInBackground because it runs on another Thread. onpre/onpostexcute runs on the main thread. If you are worried that System may terminate half way of your db operations, you shouse set Transcation, and only when you are done, you called commit.
Check out this post, I have tested it.
no, it doesn't stop.
It is relly better to put it to datastorage of some kind and then work with it
It is always better to use service for such goals. AsyncTasks just don't fit here. Ask your service to do the work, and then you may start or quit activities as you wish to.
If swiping app from recent stack, it is equivalent to close the app hence it will kill all tasks related to the process so async task will also get killed by the android system. ( even intent service is also get killed)
It is device dependent also. Manufacturers customised removing app from recents behaviour
I have an AsyncTask which creates a Notification and updates it while the progress.
But when the user exists my aplication while the AsyncTask is working, i loose the Context and I can't update anymore.
So would it be a good idea to change the function of the back button to the same function as the home button while the AsyncTask is running? Or what is another way to still have access to a Context?
I tend to avoid AsyncTasks for reasons like this. I normally use them for things that if either the activity or the task dies nothing is lost. For things that I want to make sure that will finish incase the Activity dies or if there is a problem with the background work you should probably use a Service. The platform has a basic one built in called the IntentService. This should work well for your situation since the Service will have its own context and can update and track Notifications itself.
Another alternative, which I wouldn't recommend but it is possible, is to have the main Application keep a reference to itself in a static variable. That'll also provide a Context that the task can use.
I have been reading around on internet connectivity with Android and noticed there are different ways to handle this i.e. AsyncTask and IntentService. However, I'm still not sure which one to use. My application is basically a location/trails finder with Google Maps. My internet connectivity will be used to find the nearest trails within a certain radius of the map. So, every time a user moves or swipes the map to a new location then it will update with the nearest trails. It will also add a new trail, and allow the user to rate a trail.
Will AsyncTask suffice for this or should I use IntentService?
They can be used very differently for different purposes.
AsyncTask is a handy threading utility that can be used if you need to constantly tell the user something or periodically perform operations on the main thread. It offers a lot of fine-grain control, and because of it's nature is very easy to work with in the Activity whereas an IntentService generally requires using the BroadcastReceiver or IBinder framework.
IntentService can be used very much like an AsyncTask, but it's purpose is meant for background downloading, uploading, or other blocking operations that don't need user interaction or main thread. For example, if you want to download and cache maps, you may want to call an IntentService so the user doesn't have to be looking at the app for it to download. Likewise, if you're sending data to your server, an IntentService is extremely helpful in this regard because you can start and forget. The user can, say, type a comment in your app then press "send". "Send" will launch the IntentService which gets the comment and send it off in to your server on a background thread. The user could press "send" and leave the app immediately and the comment will, eventually, still reach your servers (assuming no errors of course). If you did this with an AsyncTask in your Activity on the other hand, the system could kill off your process in the middle of your exchange and it may-or-may not go through.
Generally speaking, neither are meant for long running applications. They're meant for short, one-off operations. They could be used for permanent, or long-running actions but it's not recommended.
You should use an AsyncTask for short repetitive tasks that are tightly bound to an activity, like what you're currently trying to do. IntentService are more geared towards scheduled tasks (repetitive or not) that should run on the background, independent of your activity.
AsyncTask doesn't play well with configuration changes or other things that restart the Activity.
IntentService is good for a something that should always be available, regardless of how long it takes to do its work. I prefer IntentService in most cases because AsyncTask is so much more dependent on Activity state.
Some notes:
AsyncTask is best for quick tasks that should go right back to the UI, but it can be used in a variety of situations.
The statement "periodically perform operations on the main thread" is vague. AsyncTask spawns a new background thread that is different from the main thread, and does its work on the new thread. Thus the name AsyncTask.
An IntentService doesn't require "manipulating" the BroadcastReceiver framework. All you need to do is send a local broadcast Intent, and detect it in your Activity. Whether this is harder to do than an AsyncTask, I don't know.
IntentService is meant to do long-running tasks, which it does in the background.
AsyncTaskLoader is OK to use, but it's meant to be the base class for CursorLoader, etc.
If you want to refresh "nearby" trails when users move to a new location, an IntentService is probably better.
Don't forget to check for connectivity before trying to update location.
AsyncTasks are very tightly bound to Activitys and can often cause leaked window errors if you navigate away from the Activity that created the AsyncTask. But they are great for showing a ProgressBar because you can quickly update the progress percentage.
IntentServices are cleaner and safer. They are more difficult to implement when you are a beginner Android developer, but once you learn how to start them and handle them you will probably never go back to AsyncTasks!
IntentServices also allow for a more modular design in your app. I typically create a separate class for all my IntentServices, but for AsyncTasks I create them as an Activity inner class. If I were to separate out an AsyncTask from an Activity, I would have to pass in the Activity Context and View objects in the AsyncTask constructor which can be messy.
As mentioned above AsyncTask will solve your problem.
But Keep in mind that AsyncTask has an important weakness: it doesn't handle well Activity
"refresh" (eg during rotation). It may be a problem if, e.g., user rotate the phone while your AsyncTask is still loading stuff. If this is indeed a problem for you I recommend AsyncTaskLoader:
http://developer.android.com/reference/android/content/AsyncTaskLoader.html
AsyncTask and IntentService have many same
Can execute task in worker thread
Can run in background
Keep running till task finished event the activity which started it is destroyed
Can notify to update UI during task running or after task finish
For AsyncTask we often use onProgressUpdate, onPostExecute or if you want you can use BroadcastReceiver
For IntentService we use BroadcastReceiver
Different
1) Send task while running or after running finish
Example we have a task is: download file from server base on fileName.
Using AsyncTask
If we one instance of AsyncTask, during execute downloading file A we cannot execute download file B AsyncTask (since we get java.lang.IllegalStateException: Cannot execute task: the task is already running.). Also after downloading file A finished, we can not execute download file B (since we get java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once).
To download file B during or after download file A, we need to create new instance of AsyncTask.
=> To download file A and file B, we need 2 instance of AsyncTask => 2 worker thread created
Using IntentService
During download file A, we can sent intent to download file B => after download file A finished it will auto start download file B => don't need new instance, don't need new worker thread.
If we sent intent to download file B after download file A finished? After download file A finished, IntentSevice will destroyed (because there is no more task). Therefore, when start download file B, new instance of Service is created however no new thread created (service keep using only 1 worker thread which name is defined in IntentSevice constructor
2) Implement AsyncTask is easier than IntentService
USING
We will see that AsyncTask and IntentService have many same so in most case we can use AsyncTask or IntentService. However
I often use AsyncTask for some task that start, finish, interact with UI in 1 Activity
I often use IntentService for some task that can start/finish and interact or don't interact with UI from any Activity
This answer is base on my test. Please correct me if I am wrong. Hope it help.
In short, AsyncTask is meant for short tasks that have to communicate with main thread. IntentService is meant for long tasks that don't have to communicate with main thread.
For more info, check these links
http://www.onsandroid.com/2011/12/difference-between-android.html
https://medium.com/#skidanolegs/asynctask-vs-intentservice-1-example-without-code-5250bea6bdae
https://android.jlelse.eu/using-intentservice-vs-asynctask-in-android-2fec1b853ff4
I agree with #DeeV and #ebarrenechea about Intent service in part that you should use it for task that are not tight bound with Activity like uploading some data to server or storing data from server to database.
But starting from Android 3.0 there were introduced Loaders API Which should replace AsyncTask. So for example for loading list which you should display in Activity is better to use Loader which is designed to handle well all the configuration changes and Activity Life-cycle.
Vogella loader tutorial