La mejor manera de administrar el ProgressDialog de AsyncTask
Me gustaría usar el AsyncTask
para gestionar algunos lógica de negocio en mi aplicación. ¿Cuál es el mejor patrón para usar el onProgressUpdate(...)
de AsyncTask
definido en archivos separados (no como clase innter de Activity
) Tengo dos ideas:
1. La forma más sencilla: crear ProgressDialog
en Activity
(usando el onCreateDialog(...)
) y pasar referencia a mi subclase de AsyncTask
por constructor (override onProgressUpdate(...)
dentro de mi subclase AsyncTask
). La desventaja de esta solución es el uso de componentes de interfaz de usuario dentro del código de la lógica de negocio.
FooTask1.java:
- ¿Es una mala práctica mantener una instancia de contexto de aplicación?
- ¿Dónde debería llamarse el servicio android y llamar a GoogleAPIClient mientras se utiliza el patrón MVP en android?
- Singletons vs. Contexto de la aplicación en Android?
- ¿Deshacer / rehacer rápidamente con el patrón del memento / comando?
- ¿Cómo repetir un patrón en la vista personalizada hasta los límites?
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.El modo más sofisticado: anula el onProgressUpdate(...)
de AsyncTask
dentro de la clase Activity
:
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); } } }
- ¿Utilizando Inyección de Dependencia con Roboguice?
- Arquitectura limpia contra MVPC / MVC / MVP
- ¿Es el proveedor de contenido una implementación del patrón del repositorio?
- ¿Es Android BaseAdapter un ejemplo de patrón de adaptador?
- Práctica recomendada: Ampliación o anulación de una clase de proyecto de biblioteca de Android
- Menú del mapa de externalización
- ¿Cómo uso eficazmente un bus de eventos?
- Model View Presenter - misma vista, diferentes presentadores
Preferiría aislar las cosas de AsyncTask que aislar AsyncTask de Activity.
En general, AsyncTask tiene un diseño muy específico y el caso de uso en el ciclo de vida de la aplicación Android, es decir, ejecutar una tarea de tiempo en el hilo de fondo, una vez hecho, actualizar la vista de la actividad en el hilo de la interfaz de usuario. Por eso siempre se recomienda usarla como una clase interna de Actividad.
Un diseño más OO IMO está aislando y centralizando su lógica de negocio en un POJO (para la reutilización). Para ver si hay testabilidad, puedes 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 la unidad de prueba de su lógica de negocio, ya que es un POJO, puede utilizar puramente JUnit escribir su caso de prueba. A veces queremos probar el componente de interfaz de usuario y no nos importa cómo se implementa la lógica de negocio subyacente, por ejemplo, mi lógica de negocios se conecta al servidor http remoto descargar algunos datos json, no quiero hacerlo cada vez que sólo Quiero probar el diseño de interfaz de usuario, para esta situación, puedo cambiar fácilmente mi uso de la actividad MockBusinessDAO (tipo de concepto DI de primavera) de esta manera:
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(); } }
Algunas 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. Implementación de la lógica de negocio es puramente POJO, mejorar la reutilización.
3. La lógica de negocio de la prueba del aislamiento y el componente de la interfaz de usuario, mejoran la testabilidad.
Espero que la ayuda.
-
Solución número uno es probablemente la forma en que yo lo manejar – Esa es la forma de la estructura de Android. Un giro a esta solución (y probablemente como lo manejaría, si el
AsyncTask
no podría encajar en la clase deActivity
) pasaría unContext
como el parámetro en su lugar, y luego instanciar y mostrar elProgressDialog
enonPreExecute
. -
Solución número 2 es básicamente lo mismo que crear el diálogo como una clase interna – por lo que también podría hacer que si vas para este.