Android SQLiteDatabase transaction and AsyncTasc issue - android

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();
}
}
}

Related

ConditionVariable not working in AsyncTask

I need to wait for listener to check if image was sent correctly and then finish AsyncTask. But last log in logcat is "blocking...", so onComplete never triggers.
When I set initialization of condition varible to true, it's working but it doesn't wait on block(). I've seen many examples on ConditionVariable and I can't figure it out where my mistake is, it should be working.
private static class SendImageTask extends AsyncTask<SendImagePojo, Void, String> {
private String KOFAX_TAG = "kofax";
#Override
protected String doInBackground(SendImagePojo... params) {
Log.d(KOFAX_TAG, "doInBackground");
final ConditionVariable condition = new ConditionVariable(false);
params[0].kfx.sendImageService(params[0].doc, params[0].s, params[0].img, params[0].imageIndex, true, new ICompletionListener<Void>() {
#Override
public void onComplete(Void aVoid, Exception e) {
Log.d(KOFAX_TAG, "onComplete");
if (e != null) {
Log.e(KOFAX_TAG, e.getLocalizedMessage());
} else {
Log.d(KOFAX_TAG, "Image sent...");
}
condition.open();
}
});
Log.d(KOFAX_TAG, "blocking...");
condition.block();
Log.d(KOFAX_TAG, "continuing...");
return null;
}
}

Can't get async task to work

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.

Catch Exception of AsyncTask. Need Thinking

I want to catch exception of a thread in doInBackground and print the error message in onPostExcecute. The problem is I don't have the Throwable object in onPostExecute. How to catch Exception in non-UI thread and print the error message in UI-thread?
public class TestTask extends AsyncTask<Void, Void, List<String>> {
#Override
protected List<String> doInBackground(final Void... params) {
try {
...
return listOfString;
} catch(SomeCustomException e) {
...
return null;
}
}
#Override
protected void onPostExecute(final List<String> result) {
if(result == null) {
// print the error of the Throwable "e".
// The problem is I don't have the Throwable object here! So I can't check the type of exception.
}
}
}
Update after Arun's answer:
This is my AsyncTask wrapper class. It intends to do handling Exception in doInBackground but I can't find a good solution to do it.
public abstract class AbstractWorkerTask<Params, Progress, Result>
extends AsyncTask<Params, Progress, Result>
implements Workable {
protected OnPreExecuteListener onPreExecuteListener;
protected OnPostExecuteListener<Result> onPostExecuteListener;
protected ExceptionHappenedListener exceptionHappendedListener;
private boolean working;
#Override
protected void onPreExecute() {
if (onPreExecuteListener != null) {
onPreExecuteListener.onPreExecute();
}
working = true;
}
#Override
protected void onPostExecute(final Result result) {
working = false;
if(/* .........*/ ) {
exceptionHappendedListener.exceptionHappended(e);
}
if (onPostExecuteListener != null) {
onPostExecuteListener.onPostExecute(result);
}
}
#Override
public boolean isWorking() {
return working;
}
public void setOnPreExecuteListener(final OnPreExecuteListener onPreExecuteListener) {
this.onPreExecuteListener = onPreExecuteListener;
}
public void setOnPostExecuteListener(final OnPostExecuteListener<Result> onPostExecuteListener) {
this.onPostExecuteListener = onPostExecuteListener;
}
public void setExceptionHappendedListener(final ExceptionHappenedListener exceptionHappendedListener) {
this.exceptionHappendedListener = exceptionHappendedListener;
}
public interface OnPreExecuteListener {
void onPreExecute();
}
public interface OnPostExecuteListener<Result> {
void onPostExecute(final Result result);
}
public interface ExceptionHappenedListener {
void exceptionHappended(Exception e);
}
}
Change the return type of doInBackground() to Object and when you receive the result in onPostExecute(Object result) use the instanceOf operator to check if the returned result is an Exception or the List<String>.
Edit
Since the result can either be an Exception or else the proper List, you can use the following:
protected void onPostExecute(final Object result) {
working = false;
if(result instanceof SomeCustomException) {
exceptionHappendedListener.exceptionHappended(result);
}
else{
if (onPostExecuteListener != null) {
onPostExecuteListener.onPostExecute(result);
}
}
}
Also change the following statement:
public abstract class AbstractWorkerTask<Params, Progress, Object> extends AsyncTask<Params, Progress, Object>
Just store the Exception into a list and handle it later, as onPostExecute() is always called after doInBackground():
public class TestTask extends AsyncTask<Params, Progress, Result> {
List<Exception> exceptions = new ArrayList<Exception>();
#Override
protected Result doInBackground(Params... params) {
try {
...
} catch(SomeCustomException e) {
exceptions.add(e);
}
return result;
}
#Override
protected void onPostExecute(Result result) {
for (Exception e : exceptions) {
// Do whatever you want for the exception here
...
}
}
}
This is doable but rarely used, as in most situation, we want handle the exception as soon as it get thrown and catched:
public class TestTask extends AsyncTask<Params, Progress, Result> {
#Override
protected Result doInBackground(Params... params) {
try {
...
} catch(SomeCustomException e) {
// If you need update UI, simply do this:
runOnUiThread(new Runnable() {
public void run() {
// update your UI component here.
myTextView.setText("Exception!!!");
}
});
}
return result;
}
}
Hope this make sense.
Changing the return type of doInBackground to Object to possibly pass an Exception and then use instanceof() is a source of code smell (bad programming practice). It is always preferable to restrict your return type to the very specific thing you want returned.
Based on this answer simply add a private member to store the exception thrown in doInBackground and then check for it first thing in onPostExecute.
Only one Exception need be caught because you should stop the actions in doInBackground immediately once the exception is thrown and handle it gracefully in onPostExecute where you have access to the UI elements and so can inform the user of the mishap.
Generic example (body of the AsyncTask):
private Exception mException
#Override
protected Result doInBackground(Params... params) {
try {
// --- Do something --- //
}
catch( SomeException e ){ mException = e; return null; }
}
#Override
protected void onPostExecute(Result result) {
if (mException != null) {
// --- handle exception --- //
return;
}
// --- Perform normal post execution actions --- //
}

AsynTask - onPostExecute is called before doInBackground

i got a problem getting my AsyncTask to work correct. My App offers the possibility to connect with your Google Account and add and receive tasks by using the Tasks API. When the users wants to synchronize with his account, the doInBackground() method is started. Right before that, a ProgressDialog is displayed in the onPreExecute() method of the AsyncTask class.
If the synchronisation has been successfully executed, the onPostExecute() method 'should' be called fading out the ProgressDialog.
But there is problem: the onPostExecute() ethod is called before the work in the doInBackground() is finished.
In doInBackground() I receive the token used for the authorization:
token = future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
That's all. But right before that, the onPostExecute() is called and the ProgressDialog disappears while the token is still retrieving. The wired thing is that when I start the app and synchronizes for the first time, it works like it should. But after that the onPostExecute() method finishes before the work is completed. Does this have to do that there are requests to a server while executing
future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
How can I tell the onPostExecute() method that there is still work to do?
private class SynchronizeGoogle extends AsyncTask<Void, Integer, Void>
{
private final ProgressDialog dialog = new ProgressDialog(RememberMe.this);
protected void onPreExecute()
{
this.dialog.setMessage("Listen werden geladen...");
this.dialog.show();
}
#Override
protected Void doInBackground(Void... arg0)
{
try
{
switch(startSynchronize())
{
case 0:
publishProgress(0);
return null;
case 1:
publishProgress(1);
return null;
case 2:
publishProgress(2);
return null;
}
}
catch (IOException e)
{
e.printStackTrace();
}
synchronize();
return null;
}
protected void onProgressUpdate(Integer... type)
{
int typeCase = type[0];
switch(typeCase)
{
case 0:
showDialog(DIALOG_INTERNET_ACCESS);
break;
case 1:
showDialog(DIALOG_CREATE_ACCOUNT);
break;
case 2:
showDialog(DIALOG_ACCOUNTS);
break;
}
}
protected void onPostExecute(final Void unused)
{
if (this.dialog.isShowing())
{
this.dialog.dismiss();
}
}
}
And here my startSynchronize() and synchronize() methods:
private int startSynchronize() throws IOException
{
googleAccountManager = new GoogleAccountManager(RememberMe.this);
Account[] accounts = googleAccountManager.getAccounts();
if(checkAccess.internetAccess() == false)
{
return 0;
}
if(accounts.length == 0)
{
return 1;
}
else
{
if(accounts.length == 1)
{
account = accounts[0];
}
else
{
return 2;
}
}
return -1;
}
private void synchronize()
{
myPrefs = this.getSharedPreferences("myPrefs", MODE_PRIVATE);
String oldToken = myPrefs.getString(MY_TOKEN, "");
if(oldToken.length() > 0)
{
// invalidate old token to be able to receive a new one
googleAccountManager.invalidateAuthToken(oldToken);
}
googleAccountManager.manager.getAuthToken(account, AUTH_TOKEN_TYPE, true, new AccountManagerCallback<Bundle>()
{
public void run(AccountManagerFuture<Bundle> future)
{
try
{
token = future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
prefsEditor.putString(MY_TOKEN, token);
prefsEditor.commit();
useTasksAPI(token);
}
catch (OperationCanceledException e)
{
//...
}
catch (Exception e)
{
//...
}
}
}, null);
}
In the Optionsmenu i start it like this
new SynchronizeGoogle().execute();
Thanks everybody for your help
If I do not misunderstand your question, you're wrong with getResult() method usage.
When getResult() called by anywhere in your code, AsyncTask does not wait until finish. So you need to do your process in onPostExecute method.
I recommend you this question&answer. I hope, it's gonna help you.

AsyncTask and error handling on Android

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.

Categories

Resources