How to check if Async Task is already running - android

I have an app that needs to do an intensive database operation on start up. The app holds a local copy of the contacts on the phone and synchronizes with the android contact database on startup.
If a user starts the app, an Async Task is started that does the database synch in the background. If the user closes the app, the operation continues running which is fine. However if the user opens the app again, the Async Task is started and an error is produced.
Is there anyway of checking if the Task is already running from a different instance of the app?

Use getStatus() to get the status of your AsyncTask. If status is AsyncTask.Status.RUNNING then your task is running.
EDIT: you should reconsider your implementation and hold the AsyncTask probably in a Service or IntentService to fetch your data from the web.

I've managed to handle this problem with some sort of Singleton pattern.
Hope it helps.
// fill the places database from a JSON object
public class myAsyncTask extends AsyncTask<Void,Integer,Integer> {
Activity mContext = null;
static AsyncTask<Void,Integer,Integer> myAsyncTaskInstance = null;
// Private Constructor: can't be called from outside this class
private myAsyncTask(Activity iContext) {
mContext = iContext;
}
public static AsyncTask<Void, Integer, Integer> getInstance(Activity iContext) {
// if the current async task is already running, return null: no new async task
// shall be created if an instance is already running
if (myAsyncTaskInstance != null && myAsyncTaskInstance.getStatus() == Status.RUNNING) {
// it can be running but cancelled, in that case, return a new instance
if (myAsyncTaskInstance.isCancelled()) {
myAsyncTaskInstance = new myAsyncTask(iContext);
} else {
// display a toast to say "try later"
Toast.makeText(iContext, "A task is already running, try later", Toast.LENGTH_SHORT).show();
return null;
}
}
//if the current async task is pending, it can be executed return this instance
if (myAsyncTaskInstance != null && myAsyncTaskInstance.getStatus() == Status.PENDING) {
return myAsyncTaskInstance;
}
//if the current async task is finished, it can't be executed another time, so return a new instance
if (myAsyncTaskInstance != null && myAsyncTaskInstance.getStatus() == Status.FINISHED) {
myAsyncTaskInstance = new myAsyncTask(iContext);
}
// if the current async task is null, create a new instance
if (myAsyncTaskInstance == null) {
myAsyncTaskInstance = new myAsyncTask(iContext);
}
// return the current instance
return myAsyncTaskInstance;
}
#Override
protected Integer doInBackground(Void... iUnUsed) {
// ...
}
}

I think you should check the concept of Application in Android.
http://developer.android.com/reference/android/app/Application.html
In fact there is no such thing as
different instance of the app
. The Application is always the same for all your Activities/Services.
That means that you'd left the Activity and opened it again, 2 cases are possible:
The system already killed your application. In this case AsyncTask is dead already and it's safe to start a new one
The Application was still alive, so AsyncTask possibly still running.
In 2nd case I will recommend to use some static variables, pointing to this AsyncTask or it's state. If your app was still alive when 2nd time opened - all static references will be still valid, so you can successfully operate.
PS: By the way, in current approach be aware that your application can be terminated by the system at any time. So AsyncTask can be interrupted in any moment. It it's not ok for you - please check IntentServices - components, specially designed for background-operation purpose. http://developer.android.com/reference/android/app/IntentService.html
Good luck!

Related

How to check what the android service is currently doing once binding to it?

Let's say I have a an Android started service that does some tasks as this example:
-Service starts
-Does task A, does task B, then downloads file 1, downloads file 2, and Finally does task C.
-Service stops
Let's say while the service is doing task B, an activity binds to it. What is the correct way to check what task is the service currently doing to update the activity UI?
The way I'm doing now is by creating a Boolean flag for each task while in process and then when the activity binds to the service it checks which flag is true to send the right callback to the activity. It works, but with more tasks, it gets more complicated and even harder when errors occur.
private boolean doingTaskA = false;
private boolean doingTaskB = false;
.
.
public void doTaskA() {
// Task started, set the flag to true.
doingTaskA = true;
// send callback to update activity UI.
callback.onDoingTaskA();
// doing some API calls that takes some time to retrieve information
...
// Task finished, set to false.
doingTaskA = false;
}
public void doTaskB() {
// Task started, set the flag to true.
doingTaskB = true;
// send callback to update activity UI.
callback.onDoingTaskB();
// doing some API calls that takes some time to retrieve information
// while doing in background, an activity binds to this service (assuming
// not already bound).
...
// Task finished, set to false.
doingTaskB = false;
}
public IBinder onBind(Intent intent) {
// when binding check to see what the service is doing.
if(doingTaskA){
// send callback to update activity UI.
callback.onDoingTaskA();
}
if(doingTaskB){
// send callback to update activity UI.
callback.onDoingTaskB();
}
...
}
Please help me with efficient and reliable way of doing that.
Thanks!

AsyncTask stops when app is killed

My code runs fine, but if I go back to the home screen and return the code stops running on the text view shows nothing. Shouldn't it restart when I return to the page? It throws no errors, but if I eliminate the task and initialize the app it all over again it works but I must stay on that activity because If I go to Home and return it stops.
public class IsstatusActivity extends AppCompatActivity {
JSONParser jsonparser = new JSONParser();
TextView latitude;
TextView longitude;
String lat;
String longit;
JSONObject jobj = null;
private final ReentrantLock lock = new ReentrantLock();
private final Condition tryAgain = lock.newCondition();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.isstatus);
latitude = (TextView) findViewById(R.id.Coordinates);
longitude = (TextView) findViewById(R.id.longitude);
new Retrievedata().execute();
}
class Retrievedata extends AsyncTask<Void, String, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
while (!isCancelled()) {
jobj = jsonparser.makeHttpRequest("http://api.wheretheiss.at/v1/satellites/25544");
String lat = "latitude : " + jobj.getString("latitude");
String longit ="longitude : " + jobj.getString("longitude");
// this will cause onProgressUpdate to be called with lat & long
publishProgress(lat,longit);
// it's okay to sleep within the background thread
Thread.sleep(1500);
}
} catch (InterruptedException e) {
Log.w("RetrieveData", "thread was interrupted", e);
} catch (JSONException e) {
Log.e("RetrieveData", "parse error", e);
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
latitude.setText(values[0]);
longitude.setText(values[1]);
}
}
}
Shouldn't it restart when I return to the page?
Not necessarily. From the AsyncTask documentation:
When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
So by default the execution of AsyncTasks on versions of Android from Honeycomb onwards is serialised, meaning that only one can execute at any given time.
Looking at Retrievedata, it is set up to loop until it is cancelled (or it is interrupted or encounters a JSON related exception). However, the task isn't ever cancelled in IsstatusActivity (say, in onDestroy()), so barring interruptions or errors it will run forever (or at least until your app is killed).
Part of the reason for this is that AsyncTasks are not tied to the activity lifecycle. That means that they don't get automatically stopped when the activity they were created in finishes - rather, they keep on running until they finish whatever they're tasked with doing. Again, because Retrievedata loops until it's cancelled and this never happens, it will happily block the execution of new instances of Retrievedata created when the IsstatusActivity is subsequently started again (not to mention any other AsyncTask instances you may be using in other activities).
For more background I recommend checking out:
https://stackoverflow.com/a/13147992/2259854
http://blog.danlew.net/2014/06/21/the-hidden-pitfalls-of-asynctask/
You may be able to solve the issue by cancelling the task when you finish the activity, but as other posters have stated it may be better to avoid using AsyncTask at all for this kind of task. My understanding of AsyncTask is that it is best used for short running operations - indeed, this is what the documentation says:
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
As an aside, there's another issue with the code posted. As Retrievedata is an inner class (as opposed to being static) of IsstatusActivity, each instance of it will keep an implicit reference to the instance of IsstatusActivity it was created in. This means that even after you finish any given instance of IsstatusActivity, it will remain in memory until the Retrievedata instance created within it has finished and can be garbage collected. As per the above, this will never happen because the task runs forever.
This is called activity/context leaking. Every time IsstatusActivity is started and finished, the instance will hang around consuming memory until the app is killed. Activities are heavy objects so this is definitely something to be avoided.
Hope that helps!

How to exit all the Async task on cancellation of activity?

According to the post below:
http://techtej.blogspot.com.es/2011/03/android-thread-constructspart-4.html. It says that:
In such cases, where your application is not shutdown, but any foreground tasks have been closed or changed, all the background tasks need to know of this and try to exit gracefully
To achieve this, I am calling the cancel function on all the AsyncTask instances. Is this the right way? Also sometimes in image lazy loading, I don't keep track of all the AsyncTasks alive (and fetching images), so how to say the Android OS to cancel them too?
You can cancel AsyncTask by checking thread(AsyncTask) object's status.
private Example ex = new Example();
class Example AsyncTask<Object, Void, Void> {
#Override
protected Void doInBackground(Object... params) {
String result = null;
if(!isCancelled())
result = getHttpRestManager().send();
if(!isCancelled()) {
// some codes
}
...
return null;
}
}
public boolean cancel() {
switch(ex.getStatus()) {
case RUNNING:
case PENDING:
return ex.cancel(true);
case FINISHED:
return false;
}
return false;
}
After you cancel a thread, it's status always returns RUNNING or FINISHED. If status is not PENDING, you cannot execute thread. So you have to initialize new thread object like ex = new Example() before every .execute().
if you don't want to go back in another activity then you can use
System.exit(0);
But if there are other activities in stack,then you have to check
// AsyncTask
private Example ex = new Example();
in onDestroy method you can check it if it is running
if(ex.getStatus() == AsyncTask.Status.PENDING){
}
if(ex.getStatus() == AsyncTask.Status.RUNNING){
}
if(ex.getStatus() == AsyncTask.Status.FINISHED){
}

Check if all AsyncTasks have finished

I have 3 AsyncTasks and 1 ProgressBar. I want when any of task executes, the progress bar is visible and when all of them finish, the progress bar is invisible.
In Java, there is ExecutorService::isTerminated to check if all runnables finished but Android doesn't have it.
Update: 3 tasks execute at the same time.
Figure.
Nice graphic. But I am afraid there is no build in mechanism for this. You'll have to implement it by yourself. There are few solutions you could use -
Keep a reference to all 3 task. When task finishes check if the other two tasks are finished too, if yes than close the progress dialog if no wait for some other task to finish and check again. Make sure you free the references when you're done.
If you don't want to keep a reference store a counter. When the task finishes, increment the counter and check if it's equal to 3. If all tasks finished and you are done. If you implement this make sure to synchronized the access to the counter.
Try using AsyncTask.getStatus(). This works perfectly fine. Refer below sample code.
List<AsyncTask<String, String, String>> asyncTasks = new ArrayList<AsyncTask<String, String, String>>();
AsyncTask<String, String, String> asyncTask1 = new uploadTask().execute(string);
AsyncTask<String, String, String> asyncTask2 = new downloadTask().execute(string);
AsyncTask<String, String, String> asyncTask3 = new createTask().execute(string);
asyncTasks.add(asyncTask1);
asyncTasks.add(asyncTask2);
asyncTasks.add(asyncTask3);
You can later loop the AsyncTaskList and find each of the tasks' status as below.
for(int i=0;i<asyncTasks.size();i++){
AsyncTask<String, String, String> asyncTaskItem = (AsyncTask<String, String, String>)asyncTasks.get(i);
// getStatus() would return PENDING,RUNNING,FINISHED statuses
String status = asyncTaskItem.getStatus().toString();
//if status is FINISHED for all the 3 async tasks, hide the progressbar
}
A simple workaround would be to use three boolean variables one each for each AsyncTask and then check them accordingly.
A better approach would be to create a separate class that extends AsynTask and defines a callback interface which is fired in onPostExecute.
create a field to hold all tasks:
private ArrayList<HtmlDownloaderTask> mTasks;
Start your tasks this way:
HtmlDownloaderTask = new HtmlDownloaderTask(page.getHtml());
task.execute(page.getUrl());
//if you want parallel execution try this:
//task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,page.getUrl());
mTasks.add(task);
on the onPostExecute of MyAsyncTask:
int unfinishedTasks = 0;
for (HtmlDownloaderTask myDT : mTasks){
if(!(myDT.getStatus() == AsyncTask.Status.FINISHED)){
unfinishedTasks++;
}
}
if (unfinishedTasks == 1){
//We are all done. 1 Because its the current one that hasnt finished post execute
callWhateverMethod();
}
Well as you do know when an AsyncTask ends (when onPostExecute gets called):
one solution could be to create a method setProgressBarVisible() that keeps a counter and when first called sets visible, and a method setProgressBarInvisible() that decreases the counter and when zero sets the progress bar invisible.
:-? i think it's just a trick. you will return some message at onPostExecute of each Asyntask and compare it. (this message can contain a time, for example)
A official support of CompletableFuture was introduced since API level 24.
It's also available in Java 8 here.
Can use simply use something like:
taskA.thenCombine(taskB).thenCombine(taskC)
I would simply notify it at onPostExecute(), refer to onPostExecute and 4 steps in the document for detail and you can use EventBus to do some subscribe things.
This is a common question when you want to run a bunch of AsynTasks on a THREAD_POOL_EXECUTOR. It's much more faster than if you just call .execute() and all your tasks are done one by one.
So if you have multiple jobs and objects are not depending on each other states - try to run on a thread pool.
But the question is: how do I know that all of my tasks are done?
There is no built in methods in AsyncTask so you should do a little workaround.
In my case I added a static Hashmap field to my Asynctask class to keep track of all started and finished tasks. As a bonus of a map I can always know which task is currently in progress.
private static HashMap<Uri, Boolean> mapOfAttachmentTasks = new HashMap<>();
and ad simple three methods to access this map.
Important: they should be synchronized
public static synchronized void addTask(Uri uri){
mapOfAttachmentTasks.put(uri, true);
}
public static synchronized void removeTask(Uri uri){
mapOfAttachmentTasks.remove(uri);
}
public static synchronized boolean isTasksEmpty(){
return mapOfAttachmentTasks.isEmpty();
}
You want to add a new item to the tracking Map in an AsyncTask constructor and remove it in onPostExecute():
public AttachmentTask(Uri uri) {
this.uri = uri;
addTask(uri);
}
#Override
protected void onPostExecute(Attachment attachment) {
removeTask(uri);
if(isTasksEmpty())
EventBus.getDefault().post(new AttachmentsTaskFinishedEvent(attachment));
}
Everytime a task is finished it calls onPostEexecute and you check if it was the last task. If there is no tasks left - send a signal that you're done.
Now, here I used EventBus to send event to my Fragment but you can use a callback. In this case you should create an interface with callbackMethod, your Fragment (any of your UI components which are waiting for the event) should implement this interface and have that method. Then in AsyncTask constructor you get your Fragment as an argument and keep a reference to it, so you can call it's callback method when everything is done.
But I dont like such approach. First you need to keep the reference of your Fragment (or any other UI) in a WeakReference wrapper becasue you will get a memory leak when your fragment is dead (but still kept in memory becasue your AsyncTask has it's reference).
Also you would need to make a lot of checks and it will look something like that:
private boolean isAlive() {
return mFragmentWeakReference != null
&& mFragmentWeakReference.get() != null
&& mFragmentWeakReference.get().isAdded()
&& mFragmentWeakReference.get().getActivity() != null
&& !mFragmentWeakReference.get().getActivity().isFinishing();
yep, in production you should be a little paranoic and do all these checks :)
That's why you can use EventBus and if your UI is dead - whatever.
try this, maybe can help you...
final ImageUploader _upload = new ImageUploader();
_upload.setValue(getApplicationContext(), _imagepath, _urlPHP);
_upload.execute();
Runnable _run;
Handler _h2;
_run = new Runnable() {
public void run() {
_h2 = new Handler();
_h2.postDelayed(this, 1000);
Toast.makeText(getApplicationContext(), "not finished", Toast.LENGTH_LONG).show();
if (_upload.getStatus() == AsyncTask.Status.FINISHED) {
Toast.makeText(getApplicationContext(), "finished", Toast.LENGTH_LONG).show();
_h2.removeCallbacks(_run);
}
}
};
_h2 = new Handler();
_h2.postDelayed(_run, 1);

Android AsyncTask - avoid multiple instances running

I have AsyncTask that processes some background HTTP stuff. AsyncTask runs on schedule (Alarms/service) and sometime user executes it manually.
I process records from SQLite and I noticed double-posts on server which tells me that sometime scheduled task runs and at the same time user runs it manually causing same record to be read and processed from DB twice. I remove records after they processed but still get this.
How should I handle it ? Maybe organize some kind of queing?
You can execute your AsyncTask's on an Executor using executeOnExecutor()
To make sure that the threads are running in a serial fashion please use: SERIAL_EXECUTOR.
Misc: How to use an Executor
If several activities are accessing your DB why don't create a sort of gateway database helper and use the synchronized block to ensure only one thread has access to it at an instant
Or, you can try this to see if the Task is currently running or not:
if (katitsAsyncTask.getStatus().equals(AsyncTask.Status.FINISHED))
katitsAsyncTask.execute();
else
// wait until it's done.
Initialize the AsyncTask to null. Only create a new one if it is null. In onPostExecute, set it to null again, at the end. Do the same in onCancelled, in case the user cancels this. Here's some untested code to illustrate the basic idea.
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class FooActivity extends Activity {
private class MyAsyncTask extends AsyncTask<Foo, Foo, Foo> {
#Override
protected void onPostExecute(Foo foo) {
// do stuff
mMyAsyncTask = null;
}
#Override
protected void onCancelled() {
// TODO Auto-generated method stub
mMyAsyncTask = null;
}
#Override
protected Foo doInBackground(Foo... params) {
try {
// dangerous stuff
} catch (Exception e) {
// handle. Now we know we'll hit onPostExecute()
}
return null;
}
}
private MyAsyncTask mMyAsyncTask = null;
#Override
public void onCreate(Bundle bundle) {
Button button = (Button) findViewById(R.id.b2);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mMyAsyncTask == null) {
mMyAsyncTask = new MyAsyncTask();
mMyAsyncTask.execute(null);
}
}
});
}
}
I know this was a while ago now, and you have solved your problem. but I just had a similar problem. Reno's suggestion put me on the right track, but for those who have been finding it difficult to fill in the gaps. Here is how I overcame a similar issue to that of katit's.
I wanted a particular AsyncTask to only run if it was not currently running. And as a forward from Reno's suggestion, the AsyncTask interface has been created to handle all the nitty gritty processes in properly dealing with threads for Android. Which means, the Executor is built in. As this blog suggests:
"When execute(Object.. params) is invoked on an AsyncTask the task is executed in a background thread. Depending on the platform AsyncTasks may be executed serially (pre 1.6 and potentially again in 4+), or concurrently (1.6-3.2).
To be sure of running serially or concurrently as you require, from API Level 11 onwards you can use the executeOnExecutor(Executor executor, Object.. params) method instead, and supply an executor. The platform provides two executors for convenience, accessable as AsyncTask.SERIAL_EXECUTOR and AsyncTask.THREAD_POOL_EXECUTOR respectively. "
So with this in mind, you can do thread blocking via the AsyncTask interface, it also implies you can simply use the AsyncTasks.getStatus() to handle thread blocking, as DeeV suggests on this post.
In my code, I managed this by:
Creating a global variable defined as:
private static AsyncTask<String, Integer, String> mTask = null;
And in onCreate, initialising it as an instance of my AsyncTask called CalculateSpecAndDraw:
mTask = new CalculateAndDrawSpec();
Now when ever I wish to call this AsyncTask I surround the execute with the following:
if(mTask.getStatus() == AsyncTask.Status.FINISHED){
// My AsyncTask is done and onPostExecute was called
mTask = new CalculateAndDrawSpec().execute(Integer.toString(progress));
}else if(mTask.getStatus() == AsyncTask.Status.PENDING){
mTask.execute(Integer.toString(progress));
}else{
Toast.makeText(PlaySpecActivity.this, "Please Wait..", 1000).show();
}
This spawns a new thread if it is finished, or if the thread state is PENDING, the thread is defined but has not been started we start it. But otherwise if the thread is running we don't re-run it, we simply inform the user that it is not finished, or perform what ever action we wish. Then if you wanted to schedule the next event rather than just block it from re running, take a look at this documentation on using executors.
How about just wrapping your check-what-to-send and send-it logic in a synchronized method? This approach seems to work for us.
try having some instance boolean value that gets set to "true" on the asynctask's preexecute then "false" on postexecute. Then maybe in doinbackground check if that boolean is true. if so, then call cancel on that particular duplicate task.
You could keep the state of the task in shared preferences. Check the value (Boolean perhaps) before starting the task. Set the state to finished(true?) in onPostExecute and false in onPreExecute or in the constructor

Categories

Resources