从AsyncTask管理ProgressDialog的最佳方法

时间:2011-11-28 11:14:52

标签: android design-patterns android-asynctask

我想使用AsyncTask来管理我的应用程序中的一些业务逻辑。使用separed文件中定义的onProgressUpdate(...) AsyncTask方法的最佳模式是什么(不是Activity的内部类) 我有两个想法:
1.最简单的方法:在ProgressDialog中创建Activity(使用onCreateDialog(...)方法)并通过构造函数传递对AsyncTask的子类的引用(在我的内部覆盖onProgressUpdate(...) AsyncTask子类)。此解决方案的缺点是在业务逻辑代码中使用UI组件。

FooTask1.java:

public class FooTask1 extends AsyncTask<Void, Integer, Void> {
private ProgressDialog mProgressDialog;

public FooTask1(ProgressDialog progressDialog) {
    super();
    mProgressDialog = progressDialog;
}

@Override
protected Void doInBackground(Void... unused) {
    // time consuming operation
    for (int i=0; i<=100; i++) {
        this.publishProgress(i);
        try {
            Thread.sleep(100);
        } catch (Exception e) {}
    }
    return null;
}

@Override
protected void onProgressUpdate(Integer... progress) {
    mProgressDialog.setProgress(progress[0]);
}

@Override
protected void onPostExecute(Void result) {
    mProgressDialog.dismiss();
}
}

FooActivity1.java:

public class FooActivity1 extends Activity {

  private static final int DIALOG_PROGRESS_ID = 0;
  private ProgressDialog mProgressDialog;

  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);

      showDialog(DIALOG_PROGRESS_ID);
      new FooTask(mProgressDialog).execute();
  }

  @Override
  protected Dialog onCreateDialog(int id) {
      switch(id) {
          case DIALOG_PROGRESS_ID:
             mProgressDialog = new ProgressDialog(this);
             mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
             mProgressDialog.setMessage("Loading...");
             mProgressDialog.setCancelable(false);
             return mProgressDialog;
          default:
             return null;
      }
  }
}

2.更复杂的方式:覆盖onProgressUpdate(...)类中AsyncTask的{​​{1}}方法:

FooTask2.java:

Activity

FooActivity2.java

public class FooTask2 extends AsyncTask<Void, Integer, Void> {
@Override
protected Void doInBackground(Void... unused) {
    // time consuming operation
    for (int i=0; i<=100; i++) {
        this.publishProgress(i);
        try {
            Thread.sleep(100);
        } catch (Exception e) {}
    }
    return null;
}
}

2 个答案:

答案 0 :(得分:13)

我宁愿从AsyncTask中隔离业务逻辑内容而不是从Activity中隔离AsyncTask。

一般来说,AsyncTask在Android应用程序生命周期中有一个非常具体的设计和用例,即在后台线程中运行一些耗时的任务,一旦完成,在UI线程中更新Activity的视图。这就是为什么总是建议将它用作Activity的内部类。

更多OO设计IMO正在将您的业务逻辑隔离并集中到POJO中(以实现可重用性)。为了测试性,您可以执行以下操作:
1.定义IBusinessDAO接口 2.定义RealBusinessDAO实现IBusinessDAO
3.定义MockBusinessDAO实施IBusinessDAO
4.致电IBusinessDAO.foo();在AsyncTask.doInBackground()

对于业务逻辑的单元测试,因为它是一个POJO,您可以使用纯JUnit编写测试用例。有时候我们想测试UI组件而我们并不关心底层业务逻辑是如何实现的,例如,我的业务逻辑连接到远程http服务器下载一些json数据,我不想每次都这样做我只是想要测试UI布局,对于这种情况,我可以轻松更改我的Activity使用MockBusinessDAO(有点像Spring的DI概念),如下所示:

public class MyActivity extends Activity {
  IBusinessDAO businessDAO;

  ... ...

  private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
    ... ...        

    protected void doInBackground(Void... params) {
      businessDAO.foo();
    }
  }

  ... ...

  public void onCreate(Bundle savedInstanceState) {
    if (runInTest)
      businessDAO = new MockBusinessDAO();
    else
      businessDAO = new RealBusinessDAO();

    new myAsyncTask().execute();
  }


}

这样做的一些好处是:
1. AsyncTask实现简单而干净(doInBacnground()中的几行代码)
2.业务逻辑实现纯粹是POJO,提高了可重用性 3.隔离测试业务逻辑和UI组件,提高可测试性。

希望有所帮助。

答案 1 :(得分:1)

  1. 第一个解决方案可能就是我如何处理它 - 这就是Android框架的方式。这个解决方案的一个扭曲(可能我将如何处理它,如果AsyncTask无法适应Activity - 类)我会传递Context作为参数,而且然后实例化并在ProgressDialog中显示onPreExecute

  2. 解决方案编号2基本上与将对话框创建为内部类相同 - 所以如果你选择这个,你也可以这样做。