La mejor forma de administrar ProgressDialog desde AsyncTask

Me gustaría utilizar AsyncTask para administrar algunas lógicas comerciales en mi aplicación. ¿Cuál es el mejor patrón para usar el onProgressUpdate(...) de AsyncTask definido en archivos separados (no como una clase de Activity inter) Tengo dos ideas:
1. La forma más simple: crear ProgressDialog en Activity (usando el onCreateDialog(...) ) y pasar referencia a mi subclase de AsyncTask por constructor (anular onProgressUpdate(...) dentro de mi subclase AsyncTask ). La desventaja de esta solución es el uso de componentes de UI dentro del código de lógica de negocios.

FooTask1.java:

 public class FooTask1 extends AsyncTask { 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. La forma más sofisticada: anula el onProgressUpdate(...) de AsyncTask dentro de la clase Activity :

FooTask2.java:

 public class FooTask2 extends AsyncTask { @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); } } } 

Preferiría aislar material de lógica de negocios de AsyncTask que aislar AsyncTask de la Actividad.

En general, AsyncTask tiene un diseño muy específico y un caso de uso en el ciclo de vida de la aplicación Android, es decir, ejecuta alguna tarea que consume tiempo en el hilo de fondo, una vez hecho, actualiza la vista de la actividad en el hilo de la interfaz de usuario. Es por eso que siempre se recomienda usarlo como una clase interna de Actividad.

Un OO de diseño más OO está aislando y centralizando su lógica de negocios en un POJO (para reutilización). Para la capacidad de prueba, puede hacer algo como esto:
1. Definir una interfaz IBusinessDAO
2. Definir RealBusinessDAO implementa IBusinessDAO
3. Definir MockBusinessDAO implementa IBusinessDAO
4. Llame a IBusinessDAO.foo (); dentro de AsyncTask.doInBackground ()

Para probar la unidad de su lógica de negocios, ya que es un POJO, puede usar simplemente JUnit para escribir su caso de prueba. A veces queremos probar el componente UI y realmente no nos importa cómo se implementa la lógica empresarial subyacente, por ejemplo, mi lógica de negocios se conecta al servidor HTTP remoto para descargar algunos datos json, no quiero hacer esto cada vez que solo quiero probar el diseño de la interfaz de usuario, para esta situación, puedo cambiar fácilmente mi Actividad use MockBusinessDAO (tipo de concepto DI de Spring) de esta manera:

 public class MyActivity extends Activity { IBusinessDAO businessDAO; ... ... private class MyAsyncTask extends AsyncTask { ... ... protected void doInBackground(Void... params) { businessDAO.foo(); } } ... ... public void onCreate(Bundle savedInstanceState) { if (runInTest) businessDAO = new MockBusinessDAO(); else businessDAO = new RealBusinessDAO(); new myAsyncTask().execute(); } } 

Algunas de las ventajas de hacer esto son:
1. La implementación de AsyncTask es fácil y limpia (varias líneas de código en doInBacnground ())
2. La implementación de lógica de negocios es puramente POJO, mejora la reutilización.
3. La lógica comercial de la prueba de aislamiento y el componente UI, mejoran la capacidad de prueba.

Espero que ayudes.

  1. La solución número uno es, probablemente, cómo lo manejaría: esa es la forma del marco Android. Una vuelta de tuerca a esta solución (y probablemente cómo la manejaría, si la AsyncTask no pudiera encajar en la clase de Activity ) pasaría un Context como el parámetro en su lugar, y luego instanciaría y mostraría el ProgressDialog en onPreExecute .

  2. La solución número 2 es básicamente lo mismo que crear el diálogo como una clase interna, por lo que también puede hacer eso si elige este.