Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Programación Concurrente: Intentservice
Programación Concurrente: Intentservice
Por defecto, un proceso sólo comprende un thread, el thread principal. Todos los componentes de la
aplicación se ejecutan en este thread. Para mejorar la experiencia de usuario, Android considera que
una aplicación está bloqueada cuando no responde tras diez segundos. El usuario puede destruirla.
Para evitar tal bloqueo de la aplicación, cualquier procesamiento largo como, por ejemplo, una
descarga web o un cálculo intensivo deben realizarse en un thread secundario dedicado, liberando al
thread principal. Este último puede entonces dedicarse al funcionamiento global de la aplicación y a su
representación gráfica, tarea que se realiza de forma obligatoria en el thread principal.
Es posible crear tantos threads secundarios como se desee. Se recomienda encarecidamente crear
threads antes que procesos, pues estos últimos consumen más recursos.
Si bien no es obligatorio, en muchos casos puede ser oportuno crear servicios para ejecutar los
threads secundarios. En efecto, llegado el caso, el sistema matará de manera prioritaria aquellos
procesos que no muestren nada al usuario o los receptores de eventos sin actividad antes que los
servicios. La clase IntentServicepuede ser otra gran idea en este sentido. En efecto, permite
crear rápidamente servicios que integran un thread secundario, y gestionarlos fácilmente. Es, por
tanto, una solución suplementaria a tener en cuenta además de las que se detallan en este
capítulo.
Es común ejecutar procesamientos largos y querer visualizar sus resultados una vez terminados. O
bien, el procesamiento largo debe realizarse en un thread secundario y su visualización a través la
interfaz de usuario en el thread principal. Es preciso, por tanto, que estos threads puedan comunicarse
mutuamente.
1. AsyncTask
Como su propio nombre indica, la clase As yncTaskpermite realizar una tarea de forma asíncrona.
Es, sin duda, la forma más sencilla de crear y ejecutar un thread secundario y, a continuación, mostrar
el resultado en el thread principal.
Esta clase permite abstraerse de la manipulación de threads, y no tener que preocuparse más que
del procesamiento de fondo a realizar y de la gestión de resultados. La creación del thread
secundario se realiza de forma interna y la visualización de resultados se realiza en el thread
principal. El desarrollador no tiene que preocuparse de la creación del thread secundario, de la
gestión de estos threads ni de la comunicación entre ellos.
Es preciso, por tanto, crear una clase que herede de la clase AsyncTaske implementar los métodos
deseados. La clase Async Taskrecibe tres tipos genéricos:
Params: tipo de los parámetros pasados a la entrada de la tarea.
Sintaxis
La declaración de la clase que hereda de la clase As yncTaskse realiza generalmente como clase
privada interna al componente utilizado, como ocurre en nuestro ejemplo.
Sintaxis
Ejemplo
@Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(MiActividadPrincipal.this,
"¡Cálculo de los números primos iniciado!",
Toast.LENGTH_SHORT)
.show();
}
Sintaxis
Ejemplo
@Override
protected Integer doInBackground(Integer... arg0) {
int n = 0;
int nivel=0;
int step = (arg0[1] - arg0[0]) / 10;
for (int i = arg0[0]; i <= arg0[1]; i++) {
if (isPrime(i)) {
n++;
}
if ((i > arg0[0]) && (i % step == 0))
publishProgress(++nivel);
}
return n;
}
Ejemplo
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Toast.makeText(MiActividadPrincipal.this,
values[0]+"0% completado", Toast.LENGTH_SHORT).show();
}
Sintaxis
Ejemplo
@Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
Toast.makeText(MiActividadPrincipal.this,
result + " números primos encontrados en total.",
Toast.LENGTH_SHORT).show();
}
Es posible detener la tarea invocando a su método ca ncel. Para tener en cuenta esta
anulación lo más rápidamente posible, el procesamiento contenido en el
método doInBackground deberá verificar de forma regular el valor de retorno
del método isCan celled. En tal caso, se invocará al método onCancelled en lugar de al
método onPostExecute.
Sólo queda por utilizar esta clase para ejecutar el procesamiento. Para ello, hay que instanciar la
clase e invocar a su método exe cutepara ejecutar la tarea. Este método acepta como entrada uno
o varios parámetros del tipo genérico Params.
Una tarea sólo puede procesarse una única vez. Es preciso crear una nueva instancia para
ejecutar un nuevo procesamiento.
Sintaxis
Ejemplo
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
NumerosPrimos tarea = new NumerosPrimos();
tarea.execute(0, 10000000);
}
}
2. Thread
Si bien es práctica, la clase AsyncTaskpuede que no nos convenga en ciertos casos. Otra solución
consiste en utilizar la clase Th read. Esta clase permite definir y ejecutar un procesamiento. Es
posible ejecutar varios threads concurrentes y sincronizarlos entre ellos.
La comunicación entre este thread y el thread principal puede realizarse mediante el uso de objetos
de tipo Handler.
a. Creación
La primera forma de crear un thread consiste en instanciar la clase T hread y pasarle como
parámetro un objeto de tipo Runnable, este último permite especificar el procesamiento en su
método r un.
Sintaxis
Ejemplo
La otra forma de crear un thread consiste en instanciar una clase que herede de la clase Threade
implementando el método r un.
Sintaxis
Ejemplo
@Override
public void run() {
super.run();
Log.d(TAG, "Ejecución del procesamiento");
}
}
En ambos casos de creación del thread, la ejecución del procesamiento se realiza invocando
almétodo startdel objeto de tipo Thread.
Sintaxis
Ejemplo
b. runOnUIThread
Si un thread secundario quiere ejecutar código sobre el thread principal, por ejemplo para actualizar
directamente la interfaz de usuario, puede hacerlo utilizando el método r unOnUIThread.
Este método recibe como parámetro un objeto de tipo R unnableque contiene el código a ejecutar
en el thread principal. Esto evita tener que implementar un sistema de comunicación entre ambos
threads cuando se trata únicamente de modificar la interfaz de usuario.
Sintaxis
Ejemplo
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MiActividadPrincipal.this, "blablabla",
Toast.LENGTH_SHORT)
.show();
}
};
c. Comunicación interthread
La clase Handleres también un medio sencillo para enviar mensajes desde y hacia un
mismo thread. Esto permite planificar el procesamiento de ciertos mensajes o procesamientos
en el tiempo sin tener por qué recurrir a un sistema de alarmas o algún equivalente más
adecuado.
Estos mensajes son bien objetos de tipo Me ssage, o bien objetos de tipo Runnable. Un objeto
de tipo Messagepuede, entre otros, comportar los siguientes datos: el sujeto o tipo de mensaje
mediante un entero, dos enteros y un objeto de tipo Object.
La creación de un objeto de tipo H andler se realiza instanciando directamente a la
clase Handlerutilizando el constructor por defecto. Este handler está asociado al thread que lo ha
creado. Esto provoca que, si la instanciación tiene lugar directamente en la clase de un componente
de aplicación, el thread del handler es el thread principal. En este caso, esto permite a un thread
secundario comunicarse con el thread principal que puede modificar la interfaz de usuario.
public Handler ()
public void handleMessage (Message msg)
Ejemplo
Sintaxis
Ejemplo
También en este punto, se proveen varios métodos. El primero s endMessage, envía el mensaje y
lo procesa inmediatamente. El segundo s endMessageAtTime, envía el mensaje y lo procesará en
el momento indicado en milisegundos desde el arranque del sistema. Por último, el tercer
método, se ndMessageDelayed, envía el mensaje y lo procesa tras un tiempo de espera
especificado en milisegundos a partir de la recepción del mensaje.
Sintaxis
Ejemplo
Si los mensajes que se quiere enviar son sencillos y sólo contienen el asunto, la
clase Ha ndlerproporciona para ello métodos que tienen en cuenta la creación de estos mensajes.
La variante de los métodos propuestos es del mismo tipo que el de los métodos sendMessage.
Sintaxis
Ejemplo
Por último, como se ha indicado antes, la clase Handler permite a su vez enviar objetos de
tipo Runnablecomo mensaje. La variante de los métodos propuestos es del mismo tipo que el de
los métodos se ndMessage.
Sintaxis
Ejemplo
handler.post(new Runnable() {
public void run() {
Log.d(TAG, "Código enviado al handler");
Toast.makeText(MiActividadPrincipal.this, "Este código ha
sido enviado al handler para la ejecución en su thread.",
Toast.LENGTH_SHORT).show();
}
});
En este ejemplo, se supone que el handler ha sido creado en el thread principal. Puede, por tanto,
mostrar directamente un mensaje de tipo Toast.