I have a piece of code running the background using AsyncTask. The code is similar to this:
private class MyAsyncTask extends AsyncTask<Void, Void, Object> {
public MyAsyncTask() {
// Some init. code
}
@Override
protected Object doInBackground(Void... params) {
// Doing some long running task.
Log.v(TAG, "Finished everything. Returning ...");
return result;
}
@Override
protected void onCancelled(Object result) {
// Either way, run the next one in the line.
Log.v(TAG, "Task cancelled");
}
@Override
protected void onPostExecute(Object result) {
Log.v(TAG, "Task Completed.");
}
}
On Android 4 it works just fine, but when I run it on 2.3 (HTC Wildfire is my only test phone for now), onPostExecute is not called.
I can see the last message from doInBackground
, but none of the messages from either onCancelled
or onPostExecute
. has anyone else faced the same issue? I found this link which talks about a similar problem, but neither gives a clear solution (just suggests using normal thread instead of AsyncTask
) nor its precisely what I am looking for.
Any suggestions?
Cheers
Edit 1:
Ok, after spending a day and reading the code for AsyncTask
, Handler
, and Message
in both 2.3 and 4, I have more clues now about what is happening.
First a little bit more about my design. I have a singleton class which is used both in the app and also in some services started from my app. So the AsyncTask
code I showed above can be run either from the activity (assuming the singleton is accessed via the activity), or from the service (if the singleton is accessed via service).
Now in API 11+, no matter how the singleton is accessed, the onPostExecute
is called just fine. On API 10 and below, if the singleton is accessed from the activity, then onPostExecute
is called just fine, but if it's accessed via service, onPostExecute
is not called.
Here is more details about where it get stuck. AsyncTask
on 2.3 has an FutureTask
which overrides done
function to send a Message
to its internal Handler
as follow:
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
Message message;
Result result = null;
try {
result = get();
} catch (final InterruptedException e) {
android.util.Log.w(AsyncTask.LOG_TAG, e);
} catch (final ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (final CancellationException e) {
message = AsyncTask.sHandler.obtainMessage(AsyncTask.MESSAGE_POST_CANCEL,
new AsyncTaskResult<Result>(AsyncTask.this, (Result[]) null));
message.sendToTarget();
return;
} catch (final Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
message = AsyncTask.sHandler.obtainMessage(AsyncTask.MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
}
};
The last two lines of the following code calls message.sendToTarget
which is supposed to call handleMessage
of the Handler
class, but it does not! now I have no idea why the callback to the handler happens from an activity and not from a service! I have some solutions how to solve this (simply using AsyncTask class for API15+ in my code at all times), but any explanation about the cause of this would be very much appreciated as I have no knowledge on this!
Thanks