This is my class that i have extended from Asynctask:
public class HttpAsyncTaskSendData extends AsyncTask<String, Void, String> {
public interface SendDataCallback {
void onComplete(AsyncTask task,String nidSave, String guid);
void onError(String msg);
}
...
#Override
protected String doInBackground(String... urls) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
return PostJson.POST(urls[0], urls[1]);
}
#Override
protected void onPostExecute(String result) {
if (result != null) {
...
dataCallback.onComplete(this,res.getString("NidSave"), guid);
} else {
dataCallback.onError("No response from server");
}
}
....
}
I am using this class in my activity like this:
sendDataQueue.add(httpAsyncTaskSendData = new HttpAsyncTaskSendData(cur.getString(cur.getColumnIndex("Guid")),
cur.getString(cur.getColumnIndex("SendStateGps")), datasource, database1
, Housing, new HttpAsyncTaskSendData.SendDataCallback() {
#Override
public void onComplete(AsyncTask task ,String nidSave, String guid) {
if (task.getStatus().equals(AsyncTask.Status.FINISHED) &&
!nidSave.equals("00000000-0000-0000-0000-000000000000")) {
sendDataQueue.remove(task);
} else {
queueHasError = true;
}
if (!queueHasError) {
if (sendDataQueue.size() == 0) {
SendGps(nidSave, guid);
}
}
}
#Override
public void onError(String msg) {
queueHasError = true;
toastError(DetailsActivity.this, msg);
}
}).executeOnExecutor((AsyncTask.THREAD_POOL_EXECUTOR),
AppUtil.getConfig(DetailsActivity.this,
MainActivity.SETTING_GEO_SERVICE) + "SaveVisit/",
json.toString()));
My question is why on onComplete callback when i check Asyncktask status , this is in Running mode? and it is not in Finnish.
My onComplete callback called on onPostExecute and in this section my task should be finished its job!!! but still is running? What's is happen and what's my problem?
onPostExecute is not yet finished, thus the state of the AsyncTask is not FINISH
AsyncTask.Status
FINISHED
Indicates that AsyncTask.onPostExecute(Result) has finished.
In my application, there are multiple asynctasks. Please let me know why doInBackground of an asynctask sometimes does not getting called. Its onPreExecute method gets called. Is there any issue because of multiple asynctasks or something else?
/* ASync class for test table */
public class TestAsynch extends AsyncTask<String, Void, String>{
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String status = null;
String result1=API_Manager.getInstance().sendTestData(userName);
try {
if(result1 != null) {
// save in db
}
}
}
catch( Exception e) {
e.printStackTrace();
}
return status;
}
#Override
protected void onPostExecute(String status) {
}
}
If your project has multiple asynctasks you must check that there is a limit of asynctasks that can be executed. When you create a new AsyncTask it will be added on a Pool and will be execute only when is possible.
Check this answer:
Multitasking on android
And the docs: ThreadPoolExecutor
Here is an example on how properly handle multiple AsyncTasks AsyncTaskManager
OnPreExecute() gets called on the UI thread and doInBackground() is called on the background thread.
There is one dedicated background thread for the async task. This behaviour can be changed if you want to.
http://android-er.blogspot.in/2014/04/run-multi-asynctask-as-same-time.html
Now, say you have multiple instances of async task and I'm assuming you are calling execute() to run the async tasks. This will trigger all the preExecute immediately since UI thread is free but for the doInBackground it will triggered one by one. Hence it may take some time for the next async task to start.
doInBackground should run on a loop using a Boolean to check before execution. Before your Task is being executed, set a global boolean (may be true/false) depends on which you prefer and values add on thread should call runOnUiThread.
startExect = true;
new TestAsynch().execute();
then change this
public class TestAsynch extends AsyncTask<String, Void, String>{
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String status = null;
String result1=API_Manager.getInstance().sendTestData(userName);
try {
if(result1 != null) {
// save in db
}
}
}
catch( Exception e) {
e.printStackTrace();
}
return status;
}
#Override
protected void onPostExecute(String status) {
}
}
to this
public class TestAsynch extends AsyncTask<String, Void, String> {
String result1 = null;
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String status = null;
result1=API_Manager.getInstance().sendTestData(userName);
while (startExecute) {
Thread exe = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5);
}
catch( Exception e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
if(result1 != null) {
// save in db
}
}
});
}
}); exe.start();
}
return status;
}
#Override
protected void onPostExecute(String status) {
}
}
I think I am missing something and maybe one of you can give me a hint.
Here is what I have:
an AsyncTask with many for loops which takes paginated data from a
web service
a SQLiteDatabase which stores the retrieved data
the user
has the possibility to cancel the thread at any time by pressing a
button, case in which all the inserted/processed data needs to be
removed.
Here is how I thought of it:
public class DBAdapter {
private static SQLiteDatabase database;
private static boolean isTransactionRunning;
public void beginTransaction() {
database.beginTransaction();
isTransactionRunning = true;
}
public void endTransaction() {
database.setTransactionSuccessful();
database.endTransaction();
isTransactionRunning = false;
}
public void rollbackTransaction() {
database.endTransaction();
isTransactionRunning = false;
}
}
and on my activity I open the database and start the asynctask
protected class GetUserDataTask extends AsyncTask<Boolean, Bundle, Bundle> {
#Override
protected Bundle doInBackground(Boolean... values) {
db.beginTransaction();
for (Object obj : response.getData()) {
if (isCancelled()) {
return null;
}
///some processing
for (Object obj : response.getData()) {
if (isCancelled()) {
return null;
}
}
#Override
protected void onCancelled() {
super.onCancelled();
if (db.isTransactionRunning()) {
db.rollbackTransaction();
}
}
}
#Override
protected void onPostExecute(Bundle result) {
if (db.isTransactionRunning()) {
if (!error){
db.endTransaction()
} else{
db.rollbackTransaction();
}
}
The error I am getting, when I cancel the AsyncTask is:
java.lang.IllegalStateException: Cannot perform this operation because
there is no current transaction.
and it is happening when it fires withing onCancelled().
What am I doing wrong?
Is there a reason why you have so many places where you handle commit/rollback?
I donot know why the error happens.
But maybe it will be helpfull, if you simplify the code
eleminate the static DBAdapter.isTransactionRunning
handle beginTransaction, endTransaction and rollbackTransaction in one block
like this:
protected class GetUserDataTask extends AsyncTask<Boolean, Bundle, Bundle> {
#Override
protected Bundle doInBackground(Boolean... values) {
boolean inTransaction = true;
try {
db.beginTransaction();
for (Object obj : response.getData()) {
if (isCancelled()) {
return null;
}
///some processing
}
for (Object obj : response.getData()) {
if (isCancelled()) {
return null;
}
}
if (isCancelled()) {
return null;
}
// every thing worked well without cancel
inTransaction = false;
db.endTransaction();
return processingResult;
} finally {
if (inTransaction) {
db.rollbackTransaction();
}
}
}
I was calling a class which was performing network operations on the main thread, causing my app to blow up on more recent devices. So I've tried moving the call to the class into a AsyncTask inner class in my main activity. However now i'm getting null reference expections.
Here's my AsyncTask:
private class RetreiveAmazonNodesXML extends AsyncTask {
private Exception exception;
#Override
protected Object doInBackground(Object... params) {
try {
childrenBrowseNodesXml = new Amazon(browseNodeId, locality);
} catch (Exception e) {
this.exception = e;
}
return null;
}
}
And here's where I call it in my activity:
RetreiveAmazonNodesXML test = new RetreiveAmazonNodesXML();
test.execute();
parseXmlFile(childrenBrowseNodesXml.getBrowseNodesXML());
childrenBrowseNodesXml isn't getting updated and returning null. I know my Amazon class works fine so its something im doing with AsyncTask, but I have no idea?
Use callback for get result from async task. Here interface callback class:
public interface Callback {
public void onSuccess(Object data);
public void onError(String errorMsg);
}
And create instance this class and implement its:
final Callback resCallback = new Callback() {
#Override
public void onSuccess(Object data) {
parseXmlFile(data);
}
#Override
public void onError(String errorMsg) {
//show error with Alert or Toast
}
};
And create asynctask class with your callback:
RetreiveAmazonNodesXML test = new RetreiveAmazonNodesXML(resCallback);
test.execute(yourObjectsParams);
Write asynctask class like this:
private class RetreiveAmazonNodesXML extends AsyncTask {
private Callback responderCallback;
private Exception exception;
public GeneralHttpTask(Callback callback){
this.responderCallback = callback;
}
#Override
protected Object doInBackground(Object... params) {
try {
Amazon childrenBrowseNodesXml = new Amazon(browseNodeId, locality);
return childrenBrowseNodesXml;
} catch (Exception e) {
this.exception = e;
}
return null;
}
#Override
protected void onPostExecute(Object result) {
if(result != null) {
responderCallback.onSuccess(result);
} else {
responderCallback.onError(exception);
}
}
}
It is because you're trying to use the value that AsyncTask hasn't returned, as AsyncTask is running asyncronously.
You should put parseXmlFile(childrenBrowseNodesXml.getBrowseNodesXML()); into your AsyncTask's onPostExecute() method, like this:
private class RetreiveAmazonNodesXML extends AsyncTask {
private Exception exception;
#Override
protected Object doInBackground(Object... params) {
try {
childrenBrowseNodesXml = new Amazon(browseNodeId, locality);
} catch (Exception e) {
this.exception = e;
}
return null;
}
#Override
protected void onPostExecute(Object obj) {
parseXmlFile(childrenBrowseNodesXml.getBrowseNodesXML());
}
}
Also, return null in doInBackground method may not be a good manner, the stuff that doInBackground returns will be passed as a parameter to onPostExecute() method automatically by AsyncTask.
For more about the AsyncTask, please refer to the Android Developers: AsyncTask
The problem is, that you create a background thread (AsyncTask) that fills the childrenBrowseNodesXml after a while (when it's actually executed), but you try to use it immediately in your activity code.
Move your parseXMLFile to onPostExecute(Void result) method of AsyncTask instead.
I'm converting my code from using Handler to AsyncTask. The latter is great at what it does - asynchronous updates and handling of results in the main UI thread. What's unclear to me is how to handle exceptions if something goes haywire in AsyncTask#doInBackground.
The way I do it is to have an error Handler and send messages to it. It works fine, but is it the "right" approach or is there better alternative?
Also I understand that if I define the error Handler as an Activity field, it should execute in the UI thread. However, sometimes (very unpredictably) I will get an Exception saying that code triggered from Handler#handleMessage is executing on the wrong thread. Should I initialize error Handler in Activity#onCreate instead? Placing runOnUiThread into Handler#handleMessage seems redundant but it executes very reliably.
It works fine but is it the "right"
approach and is there better
alternative?
I hold onto the Throwable or Exception in the AsyncTask instance itself and then do something with it in onPostExecute(), so my error handling has the option of displaying a dialog on-screen.
Create an AsyncResult object ( which you can also use in other projects)
public class AsyncTaskResult<T> {
private T result;
private Exception error;
public T getResult() {
return result;
}
public Exception getError() {
return error;
}
public AsyncTaskResult(T result) {
super();
this.result = result;
}
public AsyncTaskResult(Exception error) {
super();
this.error = error;
}
}
Return this object from your AsyncTask doInBackground methods and check it in the postExecute. ( You can use this class as a base class for your other async tasks )
Below is a mockup of a task that gets a JSON response from the web server.
AsyncTask<Object,String,AsyncTaskResult<JSONObject>> jsonLoader = new AsyncTask<Object, String, AsyncTaskResult<JSONObject>>() {
#Override
protected AsyncTaskResult<JSONObject> doInBackground(
Object... params) {
try {
// get your JSONObject from the server
return new AsyncTaskResult<JSONObject>(your json object);
} catch ( Exception anyError) {
return new AsyncTaskResult<JSONObject>(anyError);
}
}
protected void onPostExecute(AsyncTaskResult<JSONObject> result) {
if ( result.getError() != null ) {
// error handling here
} else if ( isCancelled()) {
// cancel handling here
} else {
JSONObject realResult = result.getResult();
// result handling here
}
};
}
When I feel the need to handle Exceptions in AsyncTask properly, I use this as super class:
public abstract class ExceptionAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
private Exception exception=null;
private Params[] params;
#Override
final protected Result doInBackground(Params... params) {
try {
this.params = params;
return doInBackground();
}
catch (Exception e) {
exception = e;
return null;
}
}
abstract protected Result doInBackground() throws Exception;
#Override
final protected void onPostExecute(Result result) {
super.onPostExecute(result);
onPostExecute(exception, result);
}
abstract protected void onPostExecute(Exception exception, Result result);
public Params[] getParams() {
return params;
}
}
As normal, you override doInBackground in your subclass to do background work, happily throwing Exceptions where needed. You are then forced to implement onPostExecute (because it's abstract) and this gently reminds you to handle all types of Exception, which are passed as parameter. In most cases, Exceptions lead to some type of ui output, so onPostExecute is a perfect place to do that.
If you want to use the RoboGuice framework which brings you other benefits you can try the RoboAsyncTask which has an extra Callback onException(). Works real good and I use it.
http://code.google.com/p/roboguice/wiki/RoboAsyncTask
I made my own AsyncTask subclass with an interface that defines callbacks for success and failure. So if an exception is thrown in your AsyncTask, the onFailure function gets passed the exception, otherwise the onSuccess callback gets passed your result. Why android doesn't have something better available is beyond me.
public class SafeAsyncTask<inBackgroundType, progressType, resultType>
extends AsyncTask<inBackgroundType, progressType, resultType> {
protected Exception cancelledForEx = null;
protected SafeAsyncTaskInterface callbackInterface;
public interface SafeAsyncTaskInterface <cbInBackgroundType, cbResultType> {
public Object backgroundTask(cbInBackgroundType[] params) throws Exception;
public void onCancel(cbResultType result);
public void onFailure(Exception ex);
public void onSuccess(cbResultType result);
}
#Override
protected void onPreExecute() {
this.callbackInterface = (SafeAsyncTaskInterface) this;
}
#Override
protected resultType doInBackground(inBackgroundType... params) {
try {
return (resultType) this.callbackInterface.backgroundTask(params);
} catch (Exception ex) {
this.cancelledForEx = ex;
this.cancel(false);
return null;
}
}
#Override
protected void onCancelled(resultType result) {
if(this.cancelledForEx != null) {
this.callbackInterface.onFailure(this.cancelledForEx);
} else {
this.callbackInterface.onCancel(result);
}
}
#Override
protected void onPostExecute(resultType result) {
this.callbackInterface.onSuccess(result);
}
}
A more comprehensive solution to Cagatay Kalan's solution is shown below:
AsyncTaskResult
public class AsyncTaskResult<T>
{
private T result;
private Exception error;
public T getResult()
{
return result;
}
public Exception getError()
{
return error;
}
public AsyncTaskResult(T result)
{
super();
this.result = result;
}
public AsyncTaskResult(Exception error) {
super();
this.error = error;
}
}
ExceptionHandlingAsyncTask
public abstract class ExceptionHandlingAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, AsyncTaskResult<Result>>
{
private Context context;
public ExceptionHandlingAsyncTask(Context context)
{
this.context = context;
}
public Context getContext()
{
return context;
}
#Override
protected AsyncTaskResult<Result> doInBackground(Params... params)
{
try
{
return new AsyncTaskResult<Result>(doInBackground2(params));
}
catch (Exception e)
{
return new AsyncTaskResult<Result>(e);
}
}
#Override
protected void onPostExecute(AsyncTaskResult<Result> result)
{
if (result.getError() != null)
{
onPostException(result.getError());
}
else
{
onPostExecute2(result.getResult());
}
super.onPostExecute(result);
}
protected abstract Result doInBackground2(Params... params);
protected abstract void onPostExecute2(Result result);
protected void onPostException(Exception exception)
{
new AlertDialog.Builder(context).setTitle(R.string.dialog_title_generic_error).setMessage(exception.getMessage())
.setIcon(android.R.drawable.ic_dialog_alert).setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
//Nothing to do
}
}).show();
}
}
Example Task
public class ExampleTask extends ExceptionHandlingAsyncTask<String, Void, Result>
{
private ProgressDialog dialog;
public ExampleTask(Context ctx)
{
super(ctx);
dialog = new ProgressDialog(ctx);
}
#Override
protected void onPreExecute()
{
dialog.setMessage(getResources().getString(R.string.dialog_logging_in));
dialog.show();
}
#Override
protected Result doInBackground2(String... params)
{
return new Result();
}
#Override
protected void onPostExecute2(Result result)
{
if (dialog.isShowing())
dialog.dismiss();
//handle result
}
#Override
protected void onPostException(Exception exception)
{
if (dialog.isShowing())
dialog.dismiss();
super.onPostException(exception);
}
}
This simple class can help you
public abstract class ExceptionAsyncTask<Param, Progress, Result, Except extends Throwable> extends AsyncTask<Param, Progress, Result> {
private Except thrown;
#SuppressWarnings("unchecked")
#Override
/**
* Do not override this method, override doInBackgroundWithException instead
*/
protected Result doInBackground(Param... params) {
Result res = null;
try {
res = doInBackgroundWithException(params);
} catch (Throwable e) {
thrown = (Except) e;
}
return res;
}
protected abstract Result doInBackgroundWithException(Param... params) throws Except;
#Override
/**
* Don not override this method, override void onPostExecute(Result result, Except exception) instead
*/
protected void onPostExecute(Result result) {
onPostExecute(result, thrown);
super.onPostExecute(result);
}
protected abstract void onPostExecute(Result result, Except exception);
}
Another way that doesn't depend on variable member sharing is to use cancel.
This is from android docs:
public final boolean cancel (boolean mayInterruptIfRunning)
Attempts to cancel execution of this task. This
attempt will fail if the task has already completed, already been
cancelled, or could not be cancelled for some other reason. If
successful, and this task has not started when cancel is called, this
task should never run. If the task has already started, then the
mayInterruptIfRunning parameter determines whether the thread
executing this task should be interrupted in an attempt to stop the
task.
Calling this method will result in onCancelled(Object) being invoked
on the UI thread after doInBackground(Object[]) returns. Calling this
method guarantees that onPostExecute(Object) is never invoked. After
invoking this method, you should check the value returned by
isCancelled() periodically from doInBackground(Object[]) to finish the
task as early as possible.
So you can call cancel in catch statement and be sure that onPostExcute is never called, but instead onCancelled is invoked on UI thread. So you can show the error message.
Actually, AsyncTask use FutureTask & Executor, FutureTask support exception-chain
First let's define a helper class
public static class AsyncFutureTask<T> extends FutureTask<T> {
public AsyncFutureTask(#NonNull Callable<T> callable) {
super(callable);
}
public AsyncFutureTask<T> execute(#NonNull Executor executor) {
executor.execute(this);
return this;
}
public AsyncFutureTask<T> execute() {
return execute(AsyncTask.THREAD_POOL_EXECUTOR);
}
#Override
protected void done() {
super.done();
//work done, complete or abort or any exception happen
}
}
Second, let's use
try {
Log.d(TAG, new AsyncFutureTask<String>(new Callable<String>() {
#Override
public String call() throws Exception {
//throw Exception in worker thread
throw new Exception("TEST");
}
}).execute().get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
//catch the exception throw by worker thread in main thread
e.printStackTrace();
}
or use FutureTask directly like below
FutureTask<?> futureTask = new FutureTask(() -> {throw new RuntimeException("Exception in TaskRunnable");}) {
#Override
protected void done() {
super.done();
//do something
Log.d(TAG,"FutureTask done");
}
};
AsyncTask.THREAD_POOL_EXECUTOR.execute(futureTask);
try {
futureTask.get();
} catch (ExecutionException | InterruptedException e) {
Log.d(TAG, "Detect exception in futureTask", e);
}
logcat as below
Personally, I will use this approach.
You can just catch the exceptions and print out the stack trace if you need the info.
make your task in background return a boolean value.
it's like this:
#Override
protected Boolean doInBackground(String... params) {
return readXmlFromWeb(params[0]);
}
#Override
protected void onPostExecute(Boolean result) {
if(result){
// no error
}
else{
// error handling
}
}
Another possibility would be to use Object as return type, and in onPostExecute() check for the object type. It is short.
class MyAsyncTask extends AsyncTask<MyInObject, Void, Object> {
#Override
protected AsyncTaskResult<JSONObject> doInBackground(MyInObject... myInObjects) {
try {
MyOutObject result;
// ... do something that produces the result
return result;
} catch (Exception e) {
return e;
}
}
protected void onPostExecute(AsyncTaskResult<JSONObject> outcome) {
if (outcome instanceof MyOutObject) {
MyOutObject result = (MyOutObject) outcome;
// use the result
} else if (outcome instanceof Exception) {
Exception e = (Exception) outcome;
// show error message
} else throw new IllegalStateException();
}
}
If you know the correct exception then you can call the
Exception e = null;
publishProgress(int ...);
eg:
#Override
protected Object doInBackground(final String... params) {
// TODO Auto-generated method stub
try {
return mClient.call(params[0], params[1]);
} catch(final XMLRPCException e) {
// TODO Auto-generated catch block
this.e = e;
publishProgress(0);
return null;
}
}
and go to "onProgressUpdate" and do the folowing
#Override
protected void onProgressUpdate(final Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
mDialog.dismiss();
OptionPane.showMessage(mActivity, "Connection error", e.getMessage());
}
This will be helpful in some cases only. Also you can keep a Global Exception variable and access the exception.