从AsyncTask管理ProgressDialog的最佳方法

tlu*_*dek 9 android design-patterns android-asynctask

我想AsyncTask在我的应用程序中使用for来管理一些业务逻辑.使用separed文件onProgressUpdate(...)AsyncTask定义的方法的最佳模式是什么(不是作为一个类的Activity)我有两个想法:
1.最简单的方法:创建ProgressDialogin 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();
}
}
Run Code Online (Sandbox Code Playgroud)

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;
      }
  }
}
Run Code Online (Sandbox Code Playgroud)

2.更复杂的方法:覆盖类内部的onProgressUpdate(...)方法:AsyncTaskActivity

FooTask2.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;
}
}
Run Code Online (Sandbox Code Playgroud)

FooActivity2.java

public class FooActivity2 extends Activity {

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

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    showDialog(DIALOG_PROGRESS_ID);
    new FooTaskLoader().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;
    }
}

private class FooTaskLoader extends FooTask2 {
    @Override
    protected void onProgressUpdate(Integer... progress) {
        mProgressDialog.setProgress(progress[0]);
    }

    @Override
    protected void onPostExecute(Void result) {
        dismissDialog(DIALOG_PROGRESS_ID);
    }
}
}
Run Code Online (Sandbox Code Playgroud)

yor*_*rkw 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();
  }


}
Run Code Online (Sandbox Code Playgroud)

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

希望有所帮助.