miércoles, 13 de junio de 2012

Threads en Android 3: AsyncTask



Trabajando con Threads en Android III: AsyncTask

 |  | 12 Comentarios
La clase AsyncTask nos ayuda a los desarrolladores a darle un uso adecuado y más fácil al UI thread de nuestras aplicaciones. Permite ejecutar operaciones en segundo plano y definir los resultados en el UI thread sin  tener que quebrarnos la cabeza manipulandothreads y handlers.
Para utilizar AsyncTask debemos:
  • Crear una subclase de AsyncTask, comúnmente como una clase interna privada dentro de la actividad en la que estemos trabajando.
  • Sobreescribir uno o más métodos de AsyncTask para poder realizar el trabajo en segundo plano, además de cualquier otra tarea asociada para poder mostrar alguna actualización en el UI thread.
  • Cuando sea necesario, crear una instancia de AsyncTask y llamar al método execute()para que empiece a realizar su trabajo.

Tipos genéricos
AsyncTask utiliza tipos genéricos, por lo que resulta necesario definir tres tipos de datos cada vez que necesitemos crear una instancia de esta clase:
  • Parámetros (Params). El tipo de información que se necesita para procesar la tarea.
  • Progreso (Progress). El tipo de información que se pasa dentro de la tarea para indicar su progreso.
  • Resultado (Result). El tipo de información que se pasa cuando la tarea ha sido completada.
Hay que tener en cuenta que existen casos en los que algún tipo genérico no es utilizado por la AsyncTask, para ello utilizamos el tipo Void como se muestra a continuación:
Etapas del AsyncTask
Cada vez que una tarea asíncrona se ejecuta, se pasa a través de 4 etapas:
  1. onPreExceute()Se invoca en el UI thread inmediatamente después de que la tarea es ejecutada. Este paso se utiliza normalmente para configurar la tarea. El ejemplo básico es cuando se muestra una ProgressBar en la interfaz de usuario.
  2. doInBackground(Params…). Se invoca en el subproceso en segundo plano inmediatamente después de que onPreExecute() termina de ejecutarse. En esta etapa se calcula el tiempo estimado que tomará la realización de la tarea, que deberá pasarse a la última etapa de todo el proceso. Los parámetros de la tarea asíncrona también se pasan en esta etapa. Dentro de esta etapa podemos utilizar el métodopublishProgress(Progress…) para publicar una o más unidades de progreso en el UI thread por la ayuda de la siguiente etapa que es onProgressUpdate(Progress…).
  3. onProgressUpdate(Progress…)Se invoca en el UI thread después de una llamada a publishProgress(Progress…). El momento de la ejecución es indefinido. Este método es utilizado para mostrar cualquier tipo de progreso en la interfaz de usuario mientras la tarea en segundo plano sigue ejecutándose.
  4. onPostExecute(Result…). Se invoca en el UI thread después de que el proceso en segundo plano ha sido terminado. El resultado devuelto por todo el proceso se pasa a este método como parámetro.

Las reglas del juego
Para poder trabajar sin problemas con la clase AsyncTask, existen algunas reglas acerca de los threads que debes tomar en cuenta:
  • La instancia de la tarea debe crearse en el UI thread.
  • El método execute(Params…) debe invocarse en el UI thread.
  • Los métodos onPreExecute(), onPostExecute(Result), doInBackground(Params…), on ProgressUpdate(Progress…) no deben llamarse de forma manual.
  • La tarea debe ser ejecutada sólo una vez (con excepción de que la ejecución corresponda a un segundo intento).

El ejemplo
Habiendo entendido la parte teórica del asunto, es hora de saltar a la parte divertida: el código. En esta ocasión vamos a crear un ejemplo que muestre un botón que al ser presionado detone una tarea en segundo plano para actualizar el progreso en unaProgressBar. ¿Listo?
1. Creamos un nuevo proyecto llamado AsyncTaskTest con la versión Android 2.2.
2. Modificamos el archivo main.xml para agregar un botón que despliegue el texto “Go AsyncTask!” y una ProgressBar con un estilo de barra horizontal como la que ocupamos en un post anterior. A continuación el código que deberás escribir:
En la definición de la ProgressBar además de indicar el estilo con el que se mostrará, indicamos el valor máximo que alcanzará la barra (android:max) y el progreso que se mostrará cuando arranque la aplicación (android:progress).
3. Ahora pasemos a escribir el código que irá dentro de la actividad principal de la aplicación. Primero, agregamos las sentencias import de las clases que utilizaremos en el ejemplo:
import android.app.Activity;
import android.os.Bundle;
import android.widget.ProgressBar;
import android.os.AsyncTask;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
Después, definimos una subclase de AsyncTask que es una clase interna de la actividad principal; es decir, el siguiente código deberá ir dentro de las llaves que abren y cierran la definición de AsyncTaskTestActivity (en mi caso).
Como puedes ver, aquí aplicamos el uso de los tipos genéricos explicados en la parte teórica de este post al momento de crear la clase interna que he llamadoUpdateProgress. Para que todo marche bien, es necesario implementar los cuatro métodos que corresponden a las 4 etapas también comentadas líneas arriba.
  1. onPreExecute(). Definimos el progreso de la barra en 0 para empezar.
  2. doInBackground(). En este método definimos la forma en la que estará avanzando laProgressBar, para lo cual nos auxiliamos de la clase SystemClocky para cada vez que nuestra variable progress aumente se actualice su avance en el UI thread.
  3. onProgressUpdate(). Actualiza la ProgressBar.
  4. onPostExecute(). Una vez que el proceso haya terminado, el botón podrá ser presionado nuevamente después de cambiar su atributo clickable.
Por último, escribimos el código que irá dentro de la actividad y más específicamente, en el método onCreate():
public class AsyncTaskTestActivity extends Activity {
 
 Button button;
 ProgressBar progressBar;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        button = (Button)findViewById(R.id.task);
        progressBar = (ProgressBar)findViewById(R.id.progressbar);
 
        button.setOnClickListener(new Button.OnClickListener(){
         @Override
         public void onClick(View arg0){
          button.setClickable(false);
          new UpdateProgress().execute();
         }
        });
    }
   //...Definición de la clase interna
}
Recuperamos las referencias al botón y a la barra de progreso mediante sus id’s. Agregamos un evento de tipo OnClickListener en el botón, que hará que no pueda presionarse nuevamente hasta que el proceso en segundo plano finalice y que ejecutará el método execute() desde un objeto anónimo de UpdateProgress que acabamos de explicar.
4. Ahora corremos nuestro ejemplo y este es básicamente el flujo que veremos en la aplicación:
Se carga la interfaz gráfica de nuestra actividad.
Se inicia el proceso en segundo plano.
Termina el proceso en segundo plano y con ello, podemos presionar nuevamente nuestro botón.

Con este post terminamos la serie de “Trabajando con threads en Android”. Espero que te ayude a construir aplicaciones que le brinden al usuario una forma cómoda de esperar a que los procesos en segundo plano finalicen. Recuerda que hay procesos que consumen mucho tiempo (claro, si es hacen cosas interesantes como consultar en Internet, recuperar datos de una base de datos, etc.) por ello, cuida mucho la forma en la que mantienes informado a los usuarios y optimiza la forma en que esos procesos se realicen.
Para descargarte el código de este tutorial, visita nuestro repositorio en GitHub en la carpeta AsyncTaskTest.
Referencia | @EmmanuelZ3r0

No hay comentarios:

Publicar un comentario