Entendiendo la concurrencia en Android usando HaMeR

1. Introducción

Todos los que prueban el desarrollo de Android descubren la importancia de la concurrencia. La única forma de crear una aplicación receptiva es dejar el subproceso de la interfaz de usuario lo más libre posible, permitiendo que todo el trabajo duro se realice de forma asincrónica mediante subprocesos de fondo..

Debido al diseño de Android, la gestión de subprocesos utiliza solo el java.lang.threadjava.util.concurrent Los paquetes pueden ser realmente difíciles. El uso de los paquetes de subprocesos de bajo nivel con Android significa que debe preocuparse por una gran cantidad de sincronización complicada para evitar las condiciones de carrera. Afortunadamente, la gente de Google hizo el trabajo duro y construyó algunas herramientas excelentes para facilitar nuestros trabajos: AsyncTaskServicio de IntenciónCargadorAsyncQueryHandler y CursorLoader Son todos útiles, así como las clases de HaMeR. Entrenador de animales, Mensaje, y Ejecutable. Hay muchas opciones excelentes para elegir, cada una con sus ventajas y desventajas..

Mucho se ha dicho sobre el AsyncTask objeto, y muchas personas lo utilizan como un bala de plata Solución para la concurrencia en Android. Es extremadamente útil para operaciones cortas, fáciles de implementar y, probablemente, el enfoque más popular para la concurrencia en Android. Si quieres aprender más sobre AsyncTask, Echa un vistazo a las siguientes publicaciones de Envato Tuts +.

  • Android From Scratch: Operaciones de fondo

    El subprocesamiento en cualquier lenguaje de programación o plataforma es difícil, y Android no es una excepción. En este tutorial aprenderás sobre algunas de las herramientas ...
    Paul Trebilcox-Ruiz
    SDK de Android
  • Entendiendo los valores de AsyncTask en 60 segundos

    En Android, la clase AsyncTask se usa comúnmente para realizar operaciones en un hilo de fondo. En este video, te muestro cómo funciona una AsyncTask y cómo ...
    Paul Trebilcox-Ruiz
    Androide

sin embargo, AsyncTask No debería ser la única herramienta en su cinturón de herramientas..

Para operaciones de larga duración, para problemas complejos de concurrencia o para lograr una mayor eficiencia en algunas situaciones, debe elegir otra solución. Si necesita más flexibilidad o eficiencia que AsyncTask proporciona, usted podría utilizar el HaMeR (Entrenador de animales, Mensaje Y Ejecutable) marco de referencia.En este tutorial exploraremos el marco de HaMeR, uno de los modelos de concurrencia más potentes disponibles en Android, y aprenderemos cuándo y cómo usarlo. En un tutorial de seguimiento, le mostraré cómo codificar una aplicación para probar algunas posibilidades de HaMeR.

La siguiente sección presentará la importancia de los hilos de fondo para el sistema Android. Si está familiarizado con este concepto, siéntase libre de omitirlo e ir directamente a la discusión del marco de HaMeR en la sección 3.

2. La capacidad de respuesta a través de hilos de fondo

Cuando se inicia una aplicación de Android, el primer subproceso generado por su proceso es el subproceso principal, también conocido como subproceso de la interfaz de usuario, que es responsable de manejar toda la lógica de la interfaz de usuario. Este es el hilo más importante de una aplicación. Es responsable de manejar toda la interacción del usuario y también de "atar" las partes móviles de la aplicación. Android toma esto muy en serio, y si su hilo de UI se atasca trabajando en una tarea por más de unos pocos segundos, la aplicación se bloqueará.

[El subproceso de la interfaz de usuario] es muy importante porque se encarga de enviar eventos a los widgets de interfaz de usuario adecuados, incluidos los eventos de dibujo. También es el hilo en el que su aplicación interactúa con los componentes del kit de herramientas de la interfaz de usuario de Android (componentes de la android.widget y android.view paquetes). Como tal, el hilo principal a veces también se llama el hilo de la interfaz de usuario. - Procesos e hilos, Guía del desarrollador de Android

El problema es que casi todo el código en una aplicación de Android se ejecutará en el subproceso de la interfaz de usuario de forma predeterminada. Dado que las tareas en un hilo se realizan de forma secuencial, esto significa que su interfaz de usuario podría 'congelarse', y dejar de responder mientras se procesa otro trabajo..

Las tareas de larga ejecución llamadas en la interfaz de usuario probablemente serán fatales para su aplicación, y aparecerá un cuadro de diálogo ANR (aplicación que no responde). Incluso las tareas pequeñas pueden comprometer la experiencia del usuario, por lo tanto, el enfoque correcto es eliminar todo el trabajo posible del subproceso de la interfaz de usuario usando subprocesos en segundo plano. Como se dijo anteriormente, hay muchas maneras de resolver este problema, y ​​exploraremos el marco de HaMeR, una de las soluciones principales provistas por Android para enfrentar esta situación..

3. El marco de HaMeR

El marco de HaMeR permite que los subprocesos en segundo plano envíen mensajes o publiquen runnables en el subproceso de la IU y en cualquier otro subproceso Cola de mensajes a través de los controladores. HaMeR se refiere a Entrenador de animales, Mensaje, Y Ejecutable. También hay algunas otras clases importantes que trabajan junto con el HaMeR: Looper y Cola de mensajes. Juntos, esos objetos son responsables de facilitar la administración de subprocesos en Android, cuidar la sincronización y proporcionar métodos fáciles para que los subprocesos de fondo se comuniquen con la interfaz de usuario y con otros subprocesos..

Aquí es cómo las clases en el marco de HaMeR encajan.

  • Looper ejecuta un bucle de mensaje en un hilo usando el Cola de mensajes.
  • Cola de mensajes contiene una lista de mensajes a ser enviados por el Looper.
  • Entrenador de animales permite el envío y procesamiento de Mensaje y Ejecutable al Cola de mensajes. Se puede utilizar para enviar y procesar mensajes entre hilos..
  • Mensaje contiene una descripción y datos que pueden enviarse a un controlador.
  • Ejecutable representa una tarea a ejecutar.

Con el marco de trabajo de HaMeR, los subprocesos pueden enviar mensajes o publicar objetos ejecutables a sí mismos o al subproceso de la interfaz de usuario. HaMeR también promueve interacciones de hilo de fondo a través de Entrenador de animales.

3.1. La clase de manejador

Entrenador de animales es el caballo de batalla HaMeR. Es responsable de enviar Mensaje (mensaje de datos) y post Ejecutable (mensaje de tarea) objetos a la Cola de mensajes asociado con un Hilo. Después de entregar las tareas a la cola, el controlador recibe los objetos de la Looper y procesa los mensajes en el momento adecuado utilizando el Entrenador de animales asociado a ello.

UNA Entrenador de animales Se puede utilizar para enviar o publicar. Mensaje y Ejecutable objetos entre hilos, siempre que dichos hilos compartan el mismo proceso. De lo contrario, será necesario crear una Comunicación entre procesos (IPC), una metodología que supera el alcance de este tutorial..

La creación de una instancia de un controlador

UNA Entrenador de animales siempre debe estar asociado con una Looper, y esta conexión debe hacerse durante su instanciación. Si no proporciona una Looper al Entrenador de animales, estará ligado a la corriente Hiloes Looper.

// Handler usa el handler Loler Handler handler actual = new Handler (); // Handler usa el Looper, proporciona Handler handler = new Handler (Looper);

Tenga en cuenta que un Entrenador de animales siempre se asocia con un Looper, y esta conexión es permanente y no se puede cambiar una vez establecida. Sin embargo, un LooperEl hilo puede tener asociaciones con múltiples Entrenador de animaless. También es importante tener en cuenta que un Looper Debe estar activo antes de su asociación con un Entrenador de animales.

3.2. Looper y MessageQueue

El trabajo cooperativo entre Looper y Cola de mensajes en un hilo de Java crea un bucle de tareas que se procesan secuencialmente. Dicho bucle mantendrá vivo el hilo mientras espera recibir más tareas. Un hilo solo puede tener uno. Looper y uno Cola de mensajes asociado a ello; sin embargo, puede haber múltiples manejadores para cada hilo. Los manejadores son responsables de procesar las tareas en la cola, y cada tarea sabe qué manejador es responsable de su procesamiento.

3.3. Preparando un hilo para el HaMeR

La UI o el subproceso principal es el único tipo de subproceso que, de forma predeterminada, ya tiene una Entrenador de animales, una Looper, y un Cola de mensajes. Se deben preparar otros subprocesos con esos objetos antes de que puedan funcionar con el marco de trabajo de HaMeR. Primero necesitamos crear un Looper que ya incluye un Cola de mensajes y adjuntarlo al hilo. Puedes hacer esto con una subclase de Hilo, como sigue.

// Preparando un tema para la clase HaMeR LooperThread extiende el tema public Handler mHandler; public void run () // agregar y preparar el Looper Looper.prepare (); // la instancia de Handler se asociará con Thread's Looper mHandler = new Handler () public void handleMessage (Message msg) // procesa los mensajes entrantes aquí; // Iniciar el bucle de cola de mensajes utilizando el Looper Looper.loop (); 

Sin embargo, es más sencillo usar una clase de ayuda llamada HandlerThread, que tiene un Looper y un Cola de mensajes construido en un Java Hilo y está listo para recibir un controlador.

// La clase HandlerThread incluye una clase pública de Looper HamerThread extendida HandlerThread // solo necesita agregar el controlador Handler private Handler; HamerThread público (nombre de cadena) super (nombre); 

4. Publicar Runnables

los Ejecutable Es una interfaz de Java que tiene muchos usos. Podría entenderse como una sola tarea a realizar en una Hilo. Tiene un solo método que debe ser implementado., Runnable.run (), para realizar la tarea.

// Declarar un Runnable Runnable r = new Runnable () @Override public void run () // la tarea va aquí;

Hay múltiples opciones para publicar una Ejecutable en un Entrenador de animales.

  • Handler.post (Runnable r): añade el Ejecutable al Cola de mensajes.
  • Handler.postAtFrontOfQueue (Runnable r): añade el Ejecutable en el frente de la Cola de mensajes.
  • Entrenador de animales.postAtTime (Runnable r, long timeMillis): añade el Ejecutable sobre el Cola de mensajes para ser llamado en un momento específico.
  • Entrenador de animales.postDelayed (Runnable r, long delay): añade el Ejecutable a la cola que se llamará después de que haya transcurrido un tiempo específico.
// publicar un Runnable en un Handler Handler handler = new Handler (); handler.post (new Runnable () @Override public void run () // task goes here);

También es posible utilizar el controlador de UI predeterminado para publicar un Ejecutable vocación Activity.runOnUiThread ().

// publicar Runnable usando el UI Handler Activity.runOnUiThread (new Runnable () @Override public void run () // task to perform);

Es importante tener en cuenta algunas cosas acerca de Ejecutables. A diferencia de un Mensaje, una Ejecutable no se puede reciclar, una vez que se termina su trabajo, está muerto. Ya que es parte de un paquete estándar de Java, un Ejecutable no depende de Entrenador de animales y puede ser llamado en un estándar Hilo utilizando la Runnable.run () método. Sin embargo, este enfoque no tiene nada que ver con el marco de HaMeR y no compartirá ninguna de sus ventajas..

5. Enviando mensajes

los Mensaje El objeto define un mensaje que contiene una descripción y algunos datos arbitrarios que se pueden enviar y procesar a través de Entrenador de animales. los Mensaje se identifica con una En t definido en Message.what (). los Mensaje puede contener otros dos En t argumentos y un Objeto para almacenar diferentes tipos de datos.

  • Mensaje: En t identificando el Mensaje
  • Mensaje.arg1: En t argumento arbitrario
  • Mensaje.arg2: En t argumento arbitrario
  • Mensaje.obj: Objeto para almacenar diferentes tipos de datos  

Cuando necesite enviar un mensaje, en lugar de crearlo desde cero, el método recomendado es recuperar uno reciclado directamente del grupo global con el Mensaje.obtain () o Handler.obtainMessage () comandos Hay algunas versiones diferentes de esos métodos que le permiten obtener una Mensaje de acuerdo a su necesidad.

Un uso común de Handler.obtainMessage () es cuando necesitas enviar un mensaje a un hilo de fondo. Vas a utilizar el Entrenador de animales asociado con ese hilo Looper para obtener un Mensaje y enviarlo al hilo de fondo, como en el siguiente ejemplo.

int what = 0; String hello = "Hello!"; // Obtención de un mensaje asociado con un mensaje de subproceso de fondo msg = handlerBGThread.obtainMessage (what, hello); // Enviando el mensaje al controlador de subproceso de fondoBGThread.sendMessage (msg); 

Hay muchos métodos geniales en Mensaje clase, y le aconsejo que eche un vistazo más de cerca a la documentación.

5.1. enviar mensaje() Opciones

De manera similar a como podemos publicar Ejecutables, hay multiples opciones para enviar Mensajes:

  • Handler.sendMessage (Mensaje msg): Agrega un Mensaje al Cola de mensajes.
  • Handler.sendMessageAtFrontOfQueue (Mensaje msg): Agrega un Mensaje al frente de la Cola de mensajes.
  • Handler.sendMessageAtTime (Mensaje msg, long timeInMillis): Agrega un Mensaje a la cola en un momento específico.
  • Handler.sendMessageDelayed (Mensaje msg, long timeInMillis): Agrega un Mensaje a la cola después de que haya pasado un tiempo específico.

5.2. Manejo de mensajes con manejador

los Mensaje objetos despachados por Looper Son procesados ​​por el manejador con el método. Handler.handleMessage. Todo lo que tienes que hacer es extender el Entrenador de animales Clase y anular este método para procesar los mensajes..

public class MessageHandler extiende Handler @Override public void handleMessage (Message msg) switch (msg.what) // handle 'Hello' msg case 0: String hello = (String) msg.obj; System.out.println (hola); descanso; 

6. Conclusión

El marco de HaMeR puede ayudar a mejorar el código concurrente de su aplicación Android. Puede parecer confuso al principio en comparación con la simplicidad de un AsyncTask, pero la apertura de HaMeR puede ser una ventaja, si se usa correctamente. 

Recuerda:

  • Handler.post () Los métodos se utilizan cuando los remitentes saben qué operaciones realizar..
  • Handler.sendMessage() Los métodos se utilizan cuando el receptor sabe qué operación realizar..

Para obtener más información sobre el subprocesamiento en Android, puede interesarle el libro Efficient Android Threading: Técnicas de procesamiento asíncrono para aplicaciones de Android por Anders Goransson.

6.1. Que sigue?

En el siguiente tutorial, continuaremos explorando el marco de HaMeR con un enfoque práctico, mediante la creación de una aplicación que demuestre diferentes formas de usar este marco de concurrencia de Android. Crearemos esta aplicación desde cero, probando diferentes posibilidades, como la comunicación entre Trapos, hablar con el hilo de la interfaz de usuario, así como enviar mensajes y publicar Ejecutables con retrasos. 

Te veo pronto!