从AsyncTaskpipe理ProgressDialog的最佳方法
我想在我的应用程序中使用AsyncTask
来pipe理一些业务逻辑。 使用分离文件中定义的AsyncTask
的onProgressUpdate(...)
方法(不是Activity
innter类)的最佳模式是什么?我有两个想法:
1.最简单的方法:在Activity
创buildProgressDialog
(使用onCreateDialog(...)
方法)并通过构造函数(在AsyncTask
子类中覆盖onProgressUpdate(...)
)传递对AsyncTask
的子类的引用。 这个解决scheme的缺点是在业务逻辑代码中使用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, 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; } }
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中分离业务逻辑的东西,而不是从活动中分离出AsyncTask。
一般来说,AsyncTask在Android应用程序生命周期中有一个非常具体的devise和用例,就是在后台线程中运行一些耗时的任务,一旦完成,在UI线程中更新Activity的视图。 这就是为什么总是build议使用它作为Activity的内部类。
更多的面向对象devise的IMO将您的业务逻辑隔离并集中到一个POJO(可重用性)中。 为了可testing性,你可以做这样的事情:
1.定义一个接口IBusinessDAO
2.定义RealBusinessDAO实现IBusinessDAO
3.定义MockBusinessDAO实现IBusinessDAO
4.致电IBusinessDAO.foo(); 里面AsyncTask.doInBackground()
对于unit testing你的业务逻辑,因为它是一个POJO,你可以使用纯粹的JUnit编写你的testing用例。 有时候我们想testingUI组件,而且我们并不关心底层业务逻辑是如何实现的,例如,我的业务逻辑连接到远程http服务器下载一些json数据,我不想每次都只是这样做想要testingUI布局,对于这种情况,我可以很容易地改变我的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.隔离testing业务逻辑和UI组件,提高可测性。
希望有所帮助。
-
第一个解决scheme可能是我如何处理它 – 这是Android框架的方式。 这个解决scheme的一个扭曲(如果
AsyncTask
不能适应Activity
类),我可能会传递一个Context
作为参数,然后实例化并在onPreExecute
显示ProgressDialog
。 -
2号解决scheme基本上与创build内部类对话框相同 – 所以你可以这样做,如果你去这个。