Multitarea en Android


En este artículo vamos a tratar la multitarea o multi-hilo (multi-threads en inglés) en Android, que es la manera de manejar los hilos (Threads en inglés) y de esta manera poder realizar varias tareas de manera simultánea. Te invitó a que eches una ojeada a este artículo antes en el que explicamos qué es la multitarea y todas sus ventajas, tanto si ya tienes una experiencia previa como si no de la multitarea.

Al arrancar una aplicación en Android, lo que el sistema operativo Android hace es crear un nuevo proceso Linux –es decir, la aplicación ejecutándose en la memoria principal- con un único hilo en ejecución, bautizado como “hilo principal” (en inglés, main thread) o también llamado como “hilo de la Interfaz Gráfica” (en inglés, UI thread). ¿Por qué se llama “hilo de la Interfaz Gráfica”? veamos el siguiente ejemplo gráfico.

Para no empezar con la no tan divertida teoría, vamos a poner unos ejemplos muy ilustrativos.

Supongamos que tenemos una aplicación con dos botones. Un botón es para descargar datos de Internet (Imágenes, texto, etc) y el otro es para hacer otra cosa cualquiera. Ahora bien, tenemos varios trabajos (conjunto de código con una función específica, como por ejemplo el conjunto de código que se encarga de descargar datos de internet) que han de procesarse y requieren un tiempo para ello, estas van a ser para este ejemplo:

  • Toque en pantalla: es decir, calcular la posición donde el dedo ha tocado la pantalla y dar la orden de hacer lo que tenga que hacer por haberse tocado la pantalla en esa parte.
  • Dibujar en pantalla: refrescar lo que hay en la pantalla para cambiarlo. Por ejemplo, al pulsar un botón, cuando se cambia el color del botón a un color de pulsado, esto ha tenido que ser dibujado en pantalla para que el usuario lo vea.
  • Descargar datos de Internet: puede ser un fichero, una imagen, un texto, todo a la vez, lo que sea. Lo que es cierto que requerirá de un tiempo en llevarse a cabo el procesado completo.
  • Y también estaría “hacer otra cosa cualquiera”, en los ejemplos terminaremos en ella para no alargarlos innecesariamente. Es más, te lo dejo de ejercicio para que, sabiendo cómo se procesa el trabajo de “Descargar datos de Internet”, pienses un rato en como haría si “hacer otra cosa cualquiera” fuera, por ejemplo, “Buscar en una base de datos” u otra cosa que queramos que se pueda hacer en segundo plano.

Ejemplo de trabajar solo en el hilo principal

Presumamos que lo hacemos todo en el hilo principal. En la siguiente imagen, representamos el hilo principal en el tiempo con la flecha en verde. En el interior del hilo principal, de izquierda a derecha podemos ver cómo avanza el tiempo y lo que va haciendo nuestra aplicación a medida que se va usando el dispositivo (cada SmartPhone dibujado es un paso completo que corresponde con lo que está procesando el hilo principal debajo justo).

Procesando todo en el hilo principal en Android - www.Jarroba.com

Como vemos en la anterior imagen, el usuario pulsa descargar. Pero al procesarse la descarga de datos Internet en el mismo hilo que se encarga de procesar lo que vemos en la pantalla, y de procesar el toque con el dedo encima del cristal de la pantalla. El usuario queda bloqueado, a razón de que el mismo hilo principal no da abasto con tanto trabajo que tiene que hacer, primero tiene que acabar lo que ha empezado. Poniendo en cola cualquier otro trabajo, como el de tocar la pantalla y haciendo esperar al usuario (ver cara triste del usuario, que significa desinstalando la aplicación y votando negativo en Google Play en 3,2,1…). Cosa que nunca se tiene que hacer, el usuario nunca ha de esperar; es decir, el hilo principal nunca debe quedar bloqueado con mucha carga de trabajo.

Ejemplo de trabajar con el hilo principal solo para la interfaz gráfica y el resto en segundo plano

Entonces surge una pregunta ¿Puedo hacer algo concurrentemente y paralelo? (un resumen de estos términos son hacer varias cosas a la vez. Te recomiendo que leas este tutorial donde lo explicamos con detalle en el artículo sobre la multitarea que recomendamos antes). La respuesta es que podríamos realizar el trabajo de “Descargar datos de Internet” en otro hilo diferente y así liberar el hilo principal de esta carga de trabajo.

Procesando en el hilo principal y en segundo plano en Android - www.Jarroba.com

 Vemos que no bloqueamos al usuario pues puede pulsar el botón de hacer otra cosa y que funcione a la vez que se descargan los datos de Internet. En el ejemplo no llegamos a ver qué hace el botón “Otra cosa”, pero su función también podría estar en otro hilo aparte.

Seguro que te has dado cuenta del porqué al hilo principal se llama también hilo de la interfaz gráfica. Porque únicamente se debería de encargar de recoger las órdenes dadas por el usuario al dispositivo (toque en pantalla, micrófono, giroscopio, etc) y de devolverle información (dibujándola en pantalla, vibración, sonido, etc).

Por ello, para una buena programación, el hilo principal se debería encargar únicamente de:

  • Escuchar los eventos del interfaz de usuario. Es decir, hacer lo que sea al momento que se pulsa un botón, o al momento que se gira el dispositivo, o al momento que se crea un Activity, etc.
  • Dibujar en pantalla los view o widget. Es decir, mostrar todo en pantalla al usuario, como botones, imágenes, textos, etc. Todo lo que pertenece al “Android UI toolkit”.

Ya hemos visto una, pero existen dos normas a la hora de trabajar con este hilo principal:

  • No bloquear el hilo principal bajo ninguna circunstancia (más de 5 segundos bloqueado, Android lanzará un error llamado diálogo ANR -de Aplicación No Responde- que suele decir “Lo sentimos. La actividad X no está respondiendo” y deja elegir entre forzar el cierre de la aplicación o esperar a que termine de procesarse). Además, el bloqueo de este hilo hace que el usuario odie a la aplicación, pues la verá bloqueada y sin poder hacer nada de nada.
  • No acceder a nada dibujado en pantalla desde fuera del hilo principal (por ejemplo, cambiar el color de un texto desde un hilo en segundo plano dará error; todo lo que afecte a lo que se ve hay que tocarlo desde el hilo principal).

Y los hilos en segundo plano se deberían de encargar de todo lo demás. Podemos clasificar en:

  • Lógica determinada que se puede hacer en segundo plano y que pueda ser lenta. Por ejemplo, cambiar el color a todos los píxeles de una imagen en segundo plano. Como conocemos a priori el número de píxeles de la imagen (sabemos los píxeles que tiene de ancho y de alto, entonces ancho x alto nos da la cantidad de píxeles). Con lo que sabemos poner un principio y un fin. Y como está en nuestro dispositivo, conocemos la velocidad del procesador, así podemos estimar el tiempo que va a tardar en procesarse antes de empezar. Esta lógica se representa al usuario por la barra de progreso que se va llenando.

Barra de progreso Determinado en Android - www.Jarroba.com

  • Lógica indeterminada, queremos decir con esto que, no conocemos a priori nada de lo que vamos a procesar. Por ejemplo, si en segundo plano queremos descargar una imagen de internet. En este escenario no conocemos a priori el tamaño de la imagen, ni el tiempo que tardará en conectarse al servidor, ni la velocidad con la que el servidor nos transmitirá la imagen, ni nada de nada. Todo esto lo sabremos después de que la imagen se haya descargado completamente. Se representa al usuario con una animación que gira sobre su centro (como un reloj de arena, un círculo de colores, una anilla, etc).

Circulo de progreso Indeterminado en Android - www.Jarroba.com

Ya tenemos claras muchas cosas. Comentar que podemos tener varios hilos que creen otros hilos e hilos diferentes que esperen por datos de otros hilos. Vamos a ver la siguiente imagen para ver qué podemos hacer muchas cosas en segundo plano. Veremos cómo mantener todo esto controlado de una manera muy sencilla.

Programacion Multitarea en Android - www.Jarroba.com

 Como el hilo principal lanza varios hilos en segundo plano y algunos de estos hilos crean otros hilos. Eso sí, como algunos requieren datos de otros hilos al final unos han de esperar por ciertos eventos que realizan otros y con ello ser notificados. Con esto introducimos como comunicar hilos con la programación dirigida por eventos.

Lo mejor de la programación dirigida por eventos o programación orientada a eventos es que no tenemos que preguntar todo el rato a que un evento se realice, sino que dejamos programados los sucesos que queremos hacer cuando dicho evento se cumpla. Puesto en símil, encargamos una tarta al pastelero, tenemos dos opciones:

A)     Programar sin dirección por eventos. Ser unos brasas, gastando de nuestra energía y tiempo, también la del pastelero al preguntarle si nuestra tarta está lista a cada segundo: ¿Está Lista? No ¿Está lista? No ¿Está lista? No ¿Está lista? No ¿Está lista? No ¿Está lista? No ¿Está lista? Sí, cansino…

B)      Programar con dirección por eventos. Hacer otra cosa que queramos, y esperar a que el pastelero termine el evento de realizar la tarta y nos lo notifique.

Obviamente la segunda opción es la mejor. En programación la opción A es realizar un “while” hasta que pase algo; por ejemplo, preguntar todo el rato si se ha descargado cierto archivo, para al terminar hacer lo que se vaya a hacer después (pillín, te he pillado haciendo esto en más de una ocasión ¿a qué sí? 😉 ). En comparación a la opción B, que en el ejemplo con programación sería descargar cierto archivo y al terminar avisar para hacer lo que haya que hacer después (Si como programador hacías la opción A ya nunca más volverás a hacerla conociendo la programación dirigida por eventos).

He metido la palabra eventos, pero no la he explicado, seguro que por contexto has sacado buena parte del significado. Cuando ocurre algo que estamos esperando que pase (por ejemplo, esperamos que el usuario pulse un determinado botón y que ocurra algo que solo pase si se pulsa ese preciso botón), los eventos (por ejemplo, un evento es pulsar el botón descrito anteriormente, queda a la espera de lanzar el evento cuando el usuario lo pulsa) notifican a otras clases u objetos que ha ocurrido lo que esperaban. No hace falta que te aprendas los nombres, pero por si los vieras en otros lados decir que se llama editor la clase que produce el evento (pues es el encargado de editarlo propiamente, quien decide que al pulsar en el botón lo va a notificar a alguien que se suscriba a sus notificaciones), y suscriptor quien lo controla (como en las revistas, te suscribes a quien tiene eventos para que te avise cada vez que alguien haga clic en el botón. Con el mismo símil de las revistas puedes interpretar al editor como el editor de revistas, que te avisa de cuando salen al mercado).

La gracia de esta programación dirigida por eventos es que no sigue un flujo de ejecución de código (código secuencial), ejecutándose código cada vez que ocurra algo.

En Android, seguro que, has usado sin ser consciente la programación dirigida por eventos. Cada vez que usas un método que empieza por “on” estas usando este paradigma. Como el tan usado método sobrescrito “onClick()”, en el que dejas esperando al código que tiene dentro a que cuando se pulse cierto elemento se ejecute este código.

Además, por convención se usan en los métodos sobrescritos el prefijo (no hace falta que te recomiende que lo sigas si vas a crear eventos con la programación dirigida por eventos):

  • ON: para indicar que se controlará el evento sobre el hilo principal. Por ejemplo: onClick().
  • DO: para indicar que se controlará el evento sobre un hilo en segundo plano. Por ejemplo: DoInBackground().

Hemos pasado lo más difícil -y sin embargo tan fácil- ahora solo queda programar con lo aprendido. Pasemos de inmediato a aprender con todo lujo de detalle cómo se programa con AsyncTask en Android.

Ejemplo y ejercicio de modo de empleo:Si ya has trabajado algún tiempo con hilos, programación con eventos, y con Android, te recomiendo que pases por alto esta nota, pues no quiero que pierdas el tiempo en cosas que ya sabes. Sino, léela para ver si tienes los conceptos claros, y repasar los que no.Puede parecer complicado, pero mucho más lejos de la realidad; teniendo un conocimiento completo todo es mucho más sencillo. Para que no queden lagunas creo que el siguiente cuento puede merecer la pena. A medida que lo leas te recomiendo que observes la siguiente imagen. Pues haré referencia a partes de la imagen entre paréntesis. Échala un vistazo rápido, saca las conclusiones en unos pocos segundos y empieza con el cuento.

Ejemplo de Programacion Multitarea en Android - www.Jarroba.com

CUENTO:

Érase una vez un usuario que tenía un Smartphone.

El usuario instala en su dispositivo una aplicación que es una enciclopedia. Al hacer clic sobre el cuadro de búsqueda y empezar a escribir, se lanza un hilo en segundo plano que muestra las sugerencias (En la imagen anterior correspondería con el Hilo en Segundo Plano SUGERENCIAS).

Al escribir la palabra que quería, que era “pájaros”, la aplicación lanza otro hilo en segundo plano que se conecta a internet y descarga lo que necesite (Hilo en Segundo Plano DESCARGAR).

Lo primero que hace este hilo es descargar las imágenes de los pájaros y las almacena en la memoria del teléfono al lanzar este hilo a un tercero también en segundo plano (Hilo en Segundo Plano BASE DE DATOS).

Además, a la vez que descarga y almacena las imágenes, las convierte en más pequeñas para que ocupen menos, en un cuarto hilo en segundo plano (Hilo en Segundo Plano PROCESAR IMÁGENES).

Al terminar de descargar las imágenes, se descarga el texto y este se manda al terminar el hilo de descarga (Hilo en Segundo Plano SUGERENCIAS) al hilo que almacena en la base de datos (Hilo en Segundo Plano BASE DE DATOS), por lo que este tenía que esperar a que acabara el anterior para poder continuar y acabar.

Tiene un segundo problema el hilo que guarda la información (Hilo en Segundo Plano BASE DE DATOS), que también tiene que esperar a que el hilo que procesa las imágenes para que sean más pequeñas (Hilo en Segundo Plano PROCESAR IMÁGENES) también tiene que terminar, por lo que le toca esperar también a este.

Por fin, ya tenemos todos los datos necesarios descargados, guardados en la base de datos, y las imágenes empequeñecidas para que no ocuparan tanto. Se lo mandamos todo colocado al usuario, para que lo vea en pantalla y terminamos.

Y fueron felices y comieron perdices…

Es de esos cuentos que hacen lagrimear y pensar, espero que sobre todo pensar 🙂

Mira a ver si sabrías situar donde habría métodos que empiecen con “on” o “do”, qué puede ser lógica determinada o indeterminada, dónde dibujamos en pantalla, quién escucha los eventos del usuario, etc.

Comparte esta entrada en:
Safe Creative #1401310112503
Multitarea en Android por "www.jarroba.com" esta bajo una licencia Creative Commons
Reconocimiento-NoComercial-CompartirIgual 3.0 Unported License.
Creado a partir de la obra en www.jarroba.com

16 thoughts on “Multitarea en Android”

  1. Muchas gracias por tu aportacion excelente explicacion, ando buscando como enviar peticiones de maneera sincrona, a un servidor tendras algun ejemplo??

  2. Es increible la explicación!!! Mis felicitaciones y saludos, de seguro es un trabajo muy duro para que sea simple para el lector! 

  3. Yo acabo de empezar en el mundo de las app en Android y buscaba en Internet y encontraba mucha información pero que amenos a mi me costaba mucho entender porque es algo con lo que nunca había tratado, pero de repente encontré su blog, y al principio al ver muchas letras pensé que era uno de los tantos que hay, pero nunca hay que juzgar a un libro por su portada dicen por ahí.. así que siempre leo un poco para ver de que me habla y me llevé la sorpresa de que me encantó la forma en la que explican los temas, es excelente solo quería ver uno y ya me leí, la parte de multitareas también y de activity y seguire leyendo he aprendido mucho, por porsonas como ustedes nosotros podemos aprender algo nuevo. MUCHAS GRACIAS

    1. Me alegro que te haya gustado Critian, estamos trabajando muy duro en explicar las cosas de otro modo mucho más entretenido y con mucho más contenido del que parece de primeras en tan solo un artículo 🙂

  4. Muchas gracias por enseñarnos. A mí se me está clarificando la programación gracias a lo bien que explicáis.Sois especialmente buenos y didácticos enseñando, sobre todo esos ejemplos y metáforas. Es la primera vez que felicito a alguien de una web después de años navegando. Os deseo los mejores éxitos y que nuncs os canséis. Gracias

    1. Se agradecen los ánimos Federico. Buscamos conseguir justo eso, que lo que siempre nos ha costado a todos -normalmente por explicaciones demasiado técnicas que suelen dar por explicadas muchas cosas que no se deberían- se pueda obtener un conocimiento completo de una manera clara, concisa y que sea amena 🙂

  5. Excelente material el que suben, una consulta han realizado algún articulo o tutorial para el trabajo de android y base de datos, o que base de datos utilizan para este trabajo

    Recien e empezado a trabajar con android

    Saludos desde Chile

  6. Hola, muy bueno el blog enhorabuena. Pero tengo una pregunta:

    Android no te permite modificar la interfaz de pantalla en hilos secundarios, es decir que si tu tienes una tarea y esa tarea termina y quiere mostrar algo en pantalla o modificar cualquier elemento en pantalla sea un botón o editText o cosas así, este debe mandarlo al hilo principal para que lo haga ya sea con un runOnUiThread, o con los PostExecute de Asyntask que corren en UIThread.

    Mi pregunta es: yo tengo un listview con una lista dentro, y por programación quiero que al pulsar un boton en cada elemento de la lista aparezca un radiogroup, con le que el usuario selecciona caracteristcas de los elementos del listview. Esto me da error y no me deja, y esto supongo yo, que es por que cambiar eso es muy pesado para el hilo principal. ¿Qué alternativa tengo si los cambios que afectan a la interfaz no puedo hacerlos en hilos secundarios?

    Gracias un saludo.

    1. Muy buenas JC,

      no deberías tener ningún problema de velocidad a la hora dibujar el listado en pantalla con radiobuttons. Unos tips de rendimiento que te ayudarán son:
      -Asegurarse al 100% que el procesado de datos se realiza en un hilo secundario.
      -Que las entradas de los listados se generen estáticamente desde un layout XML, no desde Java.
      -Que el árbol que forma al layout sea lo más plano posible, evita que pase de 3 niveles de profundidad.
      -Cachea las entradas. Es decir, que solo se muestren y generen las entradas que el usuario ve en el momento.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies

ACEPTAR
Aviso de cookies