1. Análisis y Diseño
de Software
Departamento de Ingeniería de Sistemas Telemáticos
http://moodle.dit.upm.es
Hebras
Carlos A. Iglesias <cif@gsi.dit.upm.es>
v1.0 22/04/2013
2. Hebras 2
Temario
● 4.1 Introducción a Android
● 4.2 Introducción Desarrollo con Android
● 4.3 Ejemplo Desarrollo y Depuración
● 4.4 Actividades
● 4.5 Interfaces de Usuario
● 4.6 Intenciones
● 4.7 Acceso a Datos
● 4.8 Preferencias
● 4.9 Hebras
3. Hebras 3
Teoría
Ejercicio práctico en el ordenador
Ampliación de conocimientos
Lectura / Vídeo / Podcast
Práctica libre / Experimentación
Leyenda
5. Hebras 5
Objetivos
● Entender cómo podemos manejar hebras y
concurrencia con android
● Revisar los conceptos aprendidos de
concurrencia
6. Hebras 6
Hebras en Android
● Android se basa en Linux, por lo que utiliza
el sistema de gestión de hebras de linux
● Vamos a ver cómo usar las hebras al
programar en Android
7. Hebras 7
Ejecución Monohebra
● Por defecto, una aplicación Android ejecuta
sólo una hebra (single thread):
– Cada instrucción se ejecuta, una a
continuación de otra
– Cada llamada es bloqueante
– La hebra que se ejecuta es la hebra de interfaz
de usuario (UI thread), es responsable de
'pintar' y de capturar los eventos del usuario
– Ejecución monohebra:
8. Hebras 8
¿Qué pasa si se cuelga una
actividad?
● El sistema operativo está 'atento', y si una
actividad no responde (normalmente 5
segundos), nos avisa para que 'la
matemos'
– Diálogo ANR (Application Not Responding)
10. Hebras 10
Ejemplo
● Una aplicación que se descarga un fichero
Android in Practice, Collins et al., 2011,
Cap 6, Manning. Ejemplo disponible en
http://www.manning.org/collins
16. Hebras 16
Podemos depurar
para ver las hebras
Proceso del sistema
Nuestro proceso
1. Click – Selecciono proceso
2. Depurar
3. Depurar hebras
4. Ver hebras (actualizar)
18. Hebras 18
Análisis
● ¿Cuánto vive la hebra?
– Termina cuando termina el método run(). Puede
terminar más tarde que la Actividad / Servicio que
lo inició → No debería tener referencias a estos
objetos, puede darnos problemas
● Es una 'mala solución' – No podemos indicar
en la interfaz que hemos terminado
● ¿Qué pasa si damos muchas veces al botón?
→ Generamos muchas hebras...
19. Hebras 19
Soluciones
● Problemas para actualizar UI desde la
hebra
– Creamos varias hebras (la UI y otras) y las
comunicamos: Handler
● Problemas si piden muchas hebras
– Creamos un 'pool' de hebras y sólo tenemos
ese número activo
– Así además reutilizamos las hebras y no hace
falta crearlas cada vez: ThreadPoolExecutor
20. Hebras 20
Ejecución multihebra
● Separamos tareas 'que tardan mucho' en
diferentes hebras
● Así, simulamos mayor paralelismo, y la
interfaz responde sin penalizaciones
● Casos normales de una hebra:
– Un servicio de actualización que se ejecuta de
fondo (background)
– Un calculo que lleva mucho tiempo
– Almacenamiento de datos en tarjeta SD
21. Hebras 21
¿Cómo programamos esto en
Android?
● Definiendo un servicio que se ejecuta de
fondo y envía notificaciones a la interfaz (lo
veremos, es la 'opción mejor')
● Usando una hebra (thread) de fondo
– Usando la clase Thread y Handler directamente
• Las hebras no pueden notificar directamente a la hebra
de interfaz UI
– Usando la clase AsyncTask, que facilita ejecutar
tareas de fondo y publicar resultados en la hebra
UI principal
22. Hebras 22
Hebras
● En Android, tenemos una hebra principal,
la UIThread, que es responsable de la
interfaz
● Esta hebra puede crear otras hebras
secundarias que NO pueden acceder a la
interfaz
● La comunicación entre la hebra ppal y las
secundarias se hace con un Handler
23. Hebras 23
Handler
● Al comunicarnos con la hebra principal con
un Handler, podemos hacer dos cosas:
– Intercambiar mensajes de la cola de mensajes
del Handler
– Pasar objetos Runnables para que los ejecute
la hebra principal
http://developer.android.com/reference/android/os/Handler.html
24. Hebras 24
Comunicación hebras
Mensajes
<<Thread>>
Hebra principal (UI)
Handler h
<<Thread>>
Hebra secundaria 1
<<Thread>>
Hebra secundaria 1
<<Runnable>>
Runnable1
1. Message msg = h.obtainMessage()
2. h.sendMessage(msg)
handleMessage(Message msg)
Constructor con
patrón de diseño
Factoría para
reutilizar objetos
25. Hebras 25
Esquema paso mensajes
HebraPrincipal extends Activity {
private Handler h = new Handler() {
public void handleMessage(Message msg) {
// procesa mensajes
}
metodo() {
// crea una hebra secundaria
Thread th = new Thread(new Runnable(){
// método de la hebra secundaria
...
Message msg = h.obtainMessage();
h.sendMessage(msg);
...
});
}
}
26. Hebras 26
Comunicación hebras
Cola de Tareas
<<Thread>>
Hebra principal (UI)
Handler h
<<Thread>>
Hebra secundaria 1
<<Thread>>
Hebra secundaria 1
<<Runnable>>
Runnable r2
h.post(r1)
h.postAtFrontOfQueue(r2)
<<Runnable>>
Runnable r1
27. Hebras 27
Esquema paso tareas
HebraPrincipal extends Activity {
private Handler h = new Handler() {
public void onCreate() {
…
Thread th = new Thread(r2, “Background”);
th.start();
}
private Runnable r1 = new Runnable() {
public void run() {
// actualizo UI
}
}
private Runnable r2 = new Runnable() {
public void run() {
// ejecuto cosas
h.post(r1);
}
}
}
28. Hebras 28
Más detalle
Sólo el thread principal tiene un
objeto Looper, a través del que
accede a la cola de mensajes en
un bucle
29. Hebras 29
Ejemplo con mensajes
● Vamos a hacer una aplicación que vaya
mostrando el progreso de la tarea de fondo
● Usaremos ProgressBar
41. Hebras 41
Usando AsyncTask
● Usar las hebras directamente es tedioso
● Android proporciona AsyncTask
– Permite crear una hebra de fondo que publica
en la hebra UI sin tener que programar
Threads o Handlers
– Definimos una tarea 'asíncrona' que se ejecuta
de fondo y publica sus resultados en la hebra
UI
42. Hebras 42
AsyncTask – Uso básico
● Hebras: UI Thread (UITh) y Background Thread
(BGTh, la AsyncTask)
●Tipos genéricos: Params, Progress, Result
● Estados principales
– onPreExecute (UITh)
– doInBackground (BGTh)
– onProgressUpdate(UITh)
– onPostExecutre(UITh)
● Método auxiliar
– publishProgress (BGTh)
43. Hebras 43
AsyncTask
● Una AsyncTask tiene 3 tipos genéricos
● AsyncTask<Params, Progress, Result>
– Params – tipo de parámetros enviados a la
tarea para su ejecución
– Progress – tipo de las unidades de progreso
publicadas durante su ejecución
– Result – resultado de la ejecución de la tarea
● Si no usamos un tipo, lo ponemos Void (con
V)
44. Hebras 44
Métodos de AsyncTask
●onPreExecute(): invocado por UIth
justo tras ejecutar la tarea
●doInBackground(Params) – invocado
por BGTh justo tras onPreExecute
●onProgressUpdate(Progress) –
invocado por UITh tras una llamada de
BGTh a publishProgress(Progress)
●onPostExecute(Result) invocado por
UITh justo tras terminar BGTh
50. Hebras 50
Resumen
● En este tema hemos aprendido a gestionar
concurrencia con tareas de fondo en
Android
● Hemos visto cómo gestionar directamente
hebras, comunicarlas con Handlers, y cómo
usar AsyncTasks
● Por último, cómo darle un mejor aspecto
visual y crear recursos alternativos