如何在Android中优雅地处理AsyncTask中的异常?

时间:2022-10-24 13:52:19

I have an AsyncTask to do SQLite database migration in the background (create or upgrade). Let's say somehow an IOException or SQLiteException is thrown inside doInBackground and it's pointless for the app to continue running because database state might be not in desired state. I'm kind of confused on what to do in this situation.

我有一个AsyncTask在后台进行SQLite数据库迁移(创建或升级)。假设一个IOException或SQLiteException被抛出到doInBackground中,应用程序继续运行是没有意义的,因为数据库状态可能不在期望状态。我不知道在这种情况下该怎么做。

I'm thinking about letting the application crash as soon as possible and show dialog with error message, but I'm not really sure how to this inside doInBackground, because:

我正在考虑让应用程序尽快崩溃并显示带有错误消息的对话框,但是我不确定如何在doInBackground中实现这个,因为:

  1. This function is not executed in UI thread so I don't know if I can show a dialog.
  2. 这个函数没有在UI线程中执行,所以我不知道是否可以显示一个对话框。
  3. I don't know how to access current activity within AsyncTask, so I can't finish() it.
  4. 我不知道如何在AsyncTask中访问当前的活动,所以我无法完成()。
  5. I want to somehow throw the exception to the upper layer and let an activity handle it, but it's not possible because doInBackground doesn't list IOException as a checked exception.
  6. 我想以某种方式将异常扔给上层,让活动处理它,但这是不可能的,因为doInBackground没有将IOException列为已检查的异常。

Anyone has an advice on how to gracefully handle this situation?

有人建议如何优雅地处理这种情况吗?

3 个解决方案

#1


18  

You can't show dialog in non-ui thread. You can pass activity reference to async task. To handle this situation you can try catch the exception in doInBackground and re-throw it in onPostExecute

不能在非ui线程中显示对话框。可以将活动引用传递给async任务。要处理这种情况,可以尝试在doInBackground中捕获异常,并在onPostExecute中重新抛出异常

e.g.

如。

private class MyAsyncTaskTask extends AsyncTask<...> {

     private Activity ownerActivity;
     private Exception exceptionToBeThrown;

     public MyAsyncTaskTask(Activity activity) {
         // keep activity reference
         this.ownerActivity = activity;
     }

     protected Long doInBackground(...) {
         try {
             ...
         } catch (Exception e) {
             // save exception and re-thrown it then. 
             exceptionToBeThrown = e;
         }
     }

     protected void onPostExecute(...) {
         // Check if exception exists.
         if (exceptionToBeThrown != null) {
             ownerActivity.handleXXX();
             throw exceptionToBeThrown;
         }
     }
 }

If you async task is in Acvitiy class, then you can directly access it, e.g.,

如果异步任务在Acvitiy类中,那么可以直接访问它,例如,

public class MyActivity extends Activity {
    ...
    AsyncTask<...> task = new AsyncTask<...>() {
        public void onPostExecute(...) {
            // Access activity directly
            MyActivity.this.xxx()
        }
    }
}

#2


0  

return a unique string everytime such an exception occurs in doInBackground to onPostExecute. and in onPostExecute display a AlertDialog showing appropriate message and ask to try again or something.

每当doInBackground中出现此类异常时,返回一个惟一的字符串到onPostExecute。在onPostExecute中显示一个显示适当消息的AlertDialog请求重试。

#3


0  

My approach to handle it.

我处理它的方法。

/**
 * Created by Daniel on 02/04/2016.
 */
public abstract class AsyncTaskEnhanced<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {

    // Avoids cyclic calls.
    private boolean onPostExecuteCalled = false;
    private Exception exception;

    @Override
    protected final Result doInBackground(Params... params) {

        try {

            return this.doInBackgroundWithFaultTolerance(params);
        } catch (Exception exception) {

            this.exception = nre;
        }

        return null;
    }

    @Override
    protected final void onPostExecute(Result result) {

        if (this.onPostExecuteCalled) return;

        this.onPostExecuteCalled = true;

        super.onPostExecute(result);

        this.onPostExecuteWithFaultTolerance(result, this.exception);
    }

    protected abstract Result doInBackgroundWithFaultTolerance(Params... params) throws Exception;

    protected abstract void onPostExecuteWithFaultTolerance(Result result, Exception ex);

}

#1


18  

You can't show dialog in non-ui thread. You can pass activity reference to async task. To handle this situation you can try catch the exception in doInBackground and re-throw it in onPostExecute

不能在非ui线程中显示对话框。可以将活动引用传递给async任务。要处理这种情况,可以尝试在doInBackground中捕获异常,并在onPostExecute中重新抛出异常

e.g.

如。

private class MyAsyncTaskTask extends AsyncTask<...> {

     private Activity ownerActivity;
     private Exception exceptionToBeThrown;

     public MyAsyncTaskTask(Activity activity) {
         // keep activity reference
         this.ownerActivity = activity;
     }

     protected Long doInBackground(...) {
         try {
             ...
         } catch (Exception e) {
             // save exception and re-thrown it then. 
             exceptionToBeThrown = e;
         }
     }

     protected void onPostExecute(...) {
         // Check if exception exists.
         if (exceptionToBeThrown != null) {
             ownerActivity.handleXXX();
             throw exceptionToBeThrown;
         }
     }
 }

If you async task is in Acvitiy class, then you can directly access it, e.g.,

如果异步任务在Acvitiy类中,那么可以直接访问它,例如,

public class MyActivity extends Activity {
    ...
    AsyncTask<...> task = new AsyncTask<...>() {
        public void onPostExecute(...) {
            // Access activity directly
            MyActivity.this.xxx()
        }
    }
}

#2


0  

return a unique string everytime such an exception occurs in doInBackground to onPostExecute. and in onPostExecute display a AlertDialog showing appropriate message and ask to try again or something.

每当doInBackground中出现此类异常时,返回一个惟一的字符串到onPostExecute。在onPostExecute中显示一个显示适当消息的AlertDialog请求重试。

#3


0  

My approach to handle it.

我处理它的方法。

/**
 * Created by Daniel on 02/04/2016.
 */
public abstract class AsyncTaskEnhanced<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {

    // Avoids cyclic calls.
    private boolean onPostExecuteCalled = false;
    private Exception exception;

    @Override
    protected final Result doInBackground(Params... params) {

        try {

            return this.doInBackgroundWithFaultTolerance(params);
        } catch (Exception exception) {

            this.exception = nre;
        }

        return null;
    }

    @Override
    protected final void onPostExecute(Result result) {

        if (this.onPostExecuteCalled) return;

        this.onPostExecuteCalled = true;

        super.onPostExecute(result);

        this.onPostExecuteWithFaultTolerance(result, this.exception);
    }

    protected abstract Result doInBackgroundWithFaultTolerance(Params... params) throws Exception;

    protected abstract void onPostExecuteWithFaultTolerance(Result result, Exception ex);

}