【问题标题】:How to gracefully handle exception inside AsyncTask in Android?如何优雅地处理 Android 中 AsyncTask 中的异常?
【发布时间】:2013-01-08 09:23:31
【问题描述】:

我有一个 AsyncTask 在后台进行 SQLite 数据库迁移(创建或升级)。假设在 doInBackground 中抛出了一个 IOExceptionSQLiteException 并且应用程序继续运行是没有意义的,因为数据库状态可能不是所需的状态.我有点困惑在这种情况下该怎么做。

我正在考虑让应用程序尽快崩溃并显示带有错误消息的对话框,但我不确定如何在 doInBackground 中执行此操作,因为:

  1. 这个函数没有在UI线程中执行所以我不知道我是否可以显示一个对话框。
  2. 我不知道如何访问 AsyncTask 中的当前活动,因此无法finish()
  3. 我想以某种方式将异常抛出到上层并让活动处理它,但这是不可能的,因为 doInBackground 没有将 IOException 列为已检查异常.

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

【问题讨论】:

    标签: android exception-handling


    【解决方案1】:

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

    例如

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

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

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

    【讨论】:

    • 从异步任务中调用活动方法是一个好习惯吗?当MyActivity 死了而AsyncTask 调用MyActivity.this.xxx() 时会发生什么?
    • 或许这样可以解决问题stackoverflow.com/questions/2735102/…
    • @gkiko 调用活动方法很常见。需要处理 AsyncTask 的结果,通常需要将数据提供给视图,这意味着您需要接触 UI 线程。这样做应该是合适的。
    • 将 AsyncTask 附加到 Activity 生命周期不是一个好主意。它可能会触发内存泄漏和异常(这些最后可能被操作系统保持沉默,但它们就在那里)。当 doInBackground 方法完成时(在后台线程中),它会调用 onPostExecute 方法,但此时的外部类状态可能是意外的。 docs.oracle.com/javase/tutorial/java/javaOO/nested.html
    【解决方案2】:

    每次在 doInBackground 中发生此类异常时,将一个唯一字符串返回给 onPostExecute。并在 onPostExecute 显示一个 AlertDialog 显示适当的消息并要求重试或其他什么。

    【讨论】:

      【解决方案3】:

      我的处理方法。

      /**
       * 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);
      
      }
      

      【讨论】:

        猜你喜欢
        • 2014-07-10
        • 1970-01-01
        • 2015-12-14
        • 1970-01-01
        • 2023-03-21
        • 2017-03-04
        • 1970-01-01
        • 2016-07-30
        • 1970-01-01
        相关资源
        最近更新 更多