En esta entrada del blog voy a publicar el código de una pequeña aplicación que hice para ver si había comprendido el funcionamiento básico de este método. La aplicación simula la utilización de un bombo para obtener los números en un sorteo de la lotería Primitiva. Este no es el método más eficiente de realizar tal aplicación, pero su objetivo no era ese sino ayudarme a comprender mejor el funcionamiento de AsyncTask.
La interfaz de usuario se compone simplemente de un TextView y tres Button como se puede deducir del código que se muestra a continuación, así que me parece innecesario mostrarlo aquí.
Para ayudar a entender el funcionamiento de la aplicación, así como de la clase AsyncTask debes leer los comentarios que aparecen en el código. He intentado explicarlo con claridad para facilitar la comprensión, aunque recomiendo realizar un ejemplo para facilitar la comprensión.
package not.ebacelo.android.numerosprimitiva;
import java.util.Collections;
import java.util.Vector;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
//Definimos los elementos de la interfaz de usuario
TextView tvNumerosSeleccionados;
Button btnSeleccionarNumero;
Button btnLimpiarNumeros;
Button btnSalir;
//Definimos un objeto de la clase descendiente de AsyncTask
AsyncTaskGeneradorNumeros generador;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
//Enlazamos las variables con los controles de la interfaz de usuario
tvNumerosSeleccionados = (TextView) findViewById(R.id.tvNumerosSeleccionados);
btnSeleccionarNumero = (Button) findViewById(R.id.btnSeleccionar);
btnLimpiarNumeros = (Button) findViewById(R.id.btnLimpiar);
btnSalir = (Button) findViewById(R.id.btnSalir);
//Creamos una nueva instancia de la clase que definimos a partir de AsyncTask
//e iniciamos su ejecución
generador = new AsyncTaskGeneradorNumeros();
generador.execute();
btnSeleccionarNumero.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
generador.seleccionarNumero();
}
});
btnSalir.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Paramos y cancelamos la tarea y...
generador.parar();
generador.cancel(false);
//Finalizamos la aplicación.
finish();
}
});
btnLimpiarNumeros.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Limpiamos el TextView en el que mostramos los números obtenidos
tvNumerosSeleccionados.setText("");
//Cancelamos la ejecución y...
generador.parar();
generador.cancel(true);
//Arrancamos una nueva tarea del mismo tipo
generador = new AsyncTaskGeneradorNumeros();
generador.execute();
}
});
}
/*
* Clase que hereda de AsyncTask. Debemos sobreescribir los métodos onCancelled(),
* onPostExecute(Boolean result), onPreExecute(), onProgressUpdate(String... value) y
* doInBackground(Void... params).
* El contenido de doInBackground se ejecuta en un hilo distinto al hilo de ejecución de la
* interfaz de usuario.
* AsyncTask es una clase genérica y debemos indicar las clases que corresponden, en este caso
* son <Void, String, Boolean>. Estas clases se corresponden con <Params, Values, Result> y deben
* coincidir con la clase que se le pasa a doInBackground, a onProgressUpdate (el mismo que debe
* pasarse a la función publishProgress, que es la que provoca la ejecución de onProgressUpdate),
* y a onPostExecute (el mismo que debe devolver doInBackground).
* El hecho de establecer correctamente estos tipos es fundamental ya que de otro modo
* no funcionará, o se obtendrán resultados inesperados.
* Es importante entender que todos los métodos se ejecutan en el hilo correspondiente a la
* interfaz de usuario salvo doInBackground.
*/
private class AsyncTaskGeneradorNumeros extends AsyncTask<Void, String, Boolean> {
Vector<Integer> listaNumerosSeleccionados; //Lista para guardar los números seleccionados
private boolean cancelado = false; //Variable para parar la ejecución antes de finalizar
private boolean seleccion = false; //Variable que indica cuando hay que seleccionar un número
private boolean numMaxAlcanzado = false; //Número máximo de números a generar (6 en la Primitiva)
public boolean seleccionarNumero() {
if (!numMaxAlcanzado) {
Log.d("DEPURACION", "numMaxAlcanzado = true");
//Al poner esta variable a true, se desencadena la selección de un nuevo
//número en el método doInBackground
this.seleccion = true;
return true;
} else
return false;
}
public void parar() {
this.cancelado = true;
}
@Override
protected void onCancelled() {
super.onCancelled();
Log.d("DEPURACION", "Cancelado = true");
cancelado = true;
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
//Este método se ejecuta al finalizar la tarea que se realiza en
//el método doInBackground. El tipo del parámetro de entrada result
//debe coincidir con el valor que devuelve doInBackground y también
//con el definido en tercer lugar en la definición de la clase
//AsyncTaskGeneradorNumeros
}
@Override
protected void onPreExecute() {
super.onPreExecute();
// Inicializamos la lista de números
listaNumerosSeleccionados = new Vector<Integer>();
//Este método se ejecuta justo antes de la ejecución de doInBackground. Se
//debería utilizar para inicializar el estado.
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
// Actualizamos la lista de los números seleccionados
tvNumerosSeleccionados.setText(values[0]);
}
@Override
protected Boolean doInBackground(Void... params) {
//En este método se realiza la tarea. El código contenido dentro de este
//método se ejecutará dentro de un hilo distinto al de la interfaz de usuario
while (!cancelado && !numMaxAlcanzado) {
for (int i = 1; i < 50; i++) {
if (seleccion) {
if (!listaNumerosSeleccionados.contains(i)) {
listaNumerosSeleccionados.add(i);
if (listaNumerosSeleccionados.size() == 6)
numMaxAlcanzado = true;
String texto = "";
Collections.sort(listaNumerosSeleccionados);
for (Integer numero : listaNumerosSeleccionados)
texto += numero.toString() + " ";
//Al ejecutar publishProgress estamos haciendo que se ejecute el código
//contenido en el método onProgressUpdate recibiendo como parámetro el contenido
//de la variable texto en este caso. Este parámetro al igual que el de
//onProgressUpdate es de tipo String.
publishProgress(texto);
seleccion = false;
}
}
}
}
//Devuelve un valor del tipo Boolean
return true;
}
}
}
import java.util.Collections;
import java.util.Vector;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
//Definimos los elementos de la interfaz de usuario
TextView tvNumerosSeleccionados;
Button btnSeleccionarNumero;
Button btnLimpiarNumeros;
Button btnSalir;
//Definimos un objeto de la clase descendiente de AsyncTask
AsyncTaskGeneradorNumeros generador;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
//Enlazamos las variables con los controles de la interfaz de usuario
tvNumerosSeleccionados = (TextView) findViewById(R.id.tvNumerosSeleccionados);
btnSeleccionarNumero = (Button) findViewById(R.id.btnSeleccionar);
btnLimpiarNumeros = (Button) findViewById(R.id.btnLimpiar);
btnSalir = (Button) findViewById(R.id.btnSalir);
//Creamos una nueva instancia de la clase que definimos a partir de AsyncTask
//e iniciamos su ejecución
generador = new AsyncTaskGeneradorNumeros();
generador.execute();
btnSeleccionarNumero.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
generador.seleccionarNumero();
}
});
btnSalir.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Paramos y cancelamos la tarea y...
generador.parar();
generador.cancel(false);
//Finalizamos la aplicación.
finish();
}
});
btnLimpiarNumeros.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Limpiamos el TextView en el que mostramos los números obtenidos
tvNumerosSeleccionados.setText("");
//Cancelamos la ejecución y...
generador.parar();
generador.cancel(true);
//Arrancamos una nueva tarea del mismo tipo
generador = new AsyncTaskGeneradorNumeros();
generador.execute();
}
});
}
/*
* Clase que hereda de AsyncTask. Debemos sobreescribir los métodos onCancelled(),
* onPostExecute(Boolean result), onPreExecute(), onProgressUpdate(String... value) y
* doInBackground(Void... params).
* El contenido de doInBackground se ejecuta en un hilo distinto al hilo de ejecución de la
* interfaz de usuario.
* AsyncTask es una clase genérica y debemos indicar las clases que corresponden, en este caso
* son <Void, String, Boolean>. Estas clases se corresponden con <Params, Values, Result> y deben
* coincidir con la clase que se le pasa a doInBackground, a onProgressUpdate (el mismo que debe
* pasarse a la función publishProgress, que es la que provoca la ejecución de onProgressUpdate),
* y a onPostExecute (el mismo que debe devolver doInBackground).
* El hecho de establecer correctamente estos tipos es fundamental ya que de otro modo
* no funcionará, o se obtendrán resultados inesperados.
* Es importante entender que todos los métodos se ejecutan en el hilo correspondiente a la
* interfaz de usuario salvo doInBackground.
*/
private class AsyncTaskGeneradorNumeros extends AsyncTask<Void, String, Boolean> {
Vector<Integer> listaNumerosSeleccionados; //Lista para guardar los números seleccionados
private boolean cancelado = false; //Variable para parar la ejecución antes de finalizar
private boolean seleccion = false; //Variable que indica cuando hay que seleccionar un número
private boolean numMaxAlcanzado = false; //Número máximo de números a generar (6 en la Primitiva)
public boolean seleccionarNumero() {
if (!numMaxAlcanzado) {
Log.d("DEPURACION", "numMaxAlcanzado = true");
//Al poner esta variable a true, se desencadena la selección de un nuevo
//número en el método doInBackground
this.seleccion = true;
return true;
} else
return false;
}
public void parar() {
this.cancelado = true;
}
@Override
protected void onCancelled() {
super.onCancelled();
Log.d("DEPURACION", "Cancelado = true");
cancelado = true;
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
//Este método se ejecuta al finalizar la tarea que se realiza en
//el método doInBackground. El tipo del parámetro de entrada result
//debe coincidir con el valor que devuelve doInBackground y también
//con el definido en tercer lugar en la definición de la clase
//AsyncTaskGeneradorNumeros
}
@Override
protected void onPreExecute() {
super.onPreExecute();
// Inicializamos la lista de números
listaNumerosSeleccionados = new Vector<Integer>();
//Este método se ejecuta justo antes de la ejecución de doInBackground. Se
//debería utilizar para inicializar el estado.
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
// Actualizamos la lista de los números seleccionados
tvNumerosSeleccionados.setText(values[0]);
}
@Override
protected Boolean doInBackground(Void... params) {
//En este método se realiza la tarea. El código contenido dentro de este
//método se ejecutará dentro de un hilo distinto al de la interfaz de usuario
while (!cancelado && !numMaxAlcanzado) {
for (int i = 1; i < 50; i++) {
if (seleccion) {
if (!listaNumerosSeleccionados.contains(i)) {
listaNumerosSeleccionados.add(i);
if (listaNumerosSeleccionados.size() == 6)
numMaxAlcanzado = true;
String texto = "";
Collections.sort(listaNumerosSeleccionados);
for (Integer numero : listaNumerosSeleccionados)
texto += numero.toString() + " ";
//Al ejecutar publishProgress estamos haciendo que se ejecute el código
//contenido en el método onProgressUpdate recibiendo como parámetro el contenido
//de la variable texto en este caso. Este parámetro al igual que el de
//onProgressUpdate es de tipo String.
publishProgress(texto);
seleccion = false;
}
}
}
}
//Devuelve un valor del tipo Boolean
return true;
}
}
}
No hay comentarios:
Publicar un comentario