我想使用AsyncTask来管理我的应用程序中的一些业务逻辑.使用在separed文件中定义的AsyncTask的onProgressUpdate(…)方法的最佳模式是什么(而不是作为一个活动类别)
我有两个想法:
1.最简单的方法:在Activity中创建ProgressDialog(使用onCreateDialog(…)方法),并通过构造函数(在AsyncTask子类中覆盖onProgressUpdate(…))将引用传递给AsyncTask的子类.这个解决方案的缺点在于在业务逻辑代码中使用UI组件.
我有两个想法:
1.最简单的方法:在Activity中创建ProgressDialog(使用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.更复杂的方法:在Activity类中覆盖AsyncTask的onProgressUpdate(…)方法:
FooTask2.java:
public class FooTask2 extends AsyncTask<Void,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; } }
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); } } }
解决方法
我宁愿从AsyncTask中隔离业务逻辑,而不是从Activity中分离AsyncTask.
一般来说,AsyncTask在Android应用程序生命周期中有一个非常具体的设计和用例,即在后台线程中运行一些耗时的任务,一旦完成,在UI线程中更新Activity的视图.这就是为什么总是推荐使用它作为一个内部的活动类.
更多的OO设计IMO将您的业务逻辑隔离并集中到POJO(为了可重用性).为了可测试性,您可以这样做:
1.定义界面IBusinessDAO
2.定义RealBusinessDAO实现IBusinessDAO
3.定义MockBusinessDAO实现IBusinessDAO
调用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()中的几行代码)
业务逻辑实现纯粹是POJO,提高可重用性.
3.隔离测试业务逻辑和UI组件,提高可测试性.
希望有帮助