Comprender el núcleo de Android: Looper, Handler y HandlerThread

Descripción del núcleo de Android: Looper, Handler y HandlerThread

Este artículo cubre Android Looper, Handler y HandlerThread. Estos son algunos de los bloques de construcción del sistema operativo Android.

En mi propia experiencia, los he utilizado en un contexto muy limitado hasta hace poco. Mi caso de uso consistió en enviar tareas al subproceso principal/iu, principalmente para actualizar la IU desde cualquier otro subproceso. Los otros aspectos de la operación de subprocesos múltiples se manejaron a través de formas alternativas como ThreadPoolExecutor, IntentService y AsyncTask.

Los subprocesos múltiples y la ejecución de tareas son temas antiguos. Java en sí tiene Java.útil.paquete simultáneo y marco de unión/bifurcación para facilitarlo. Se han escrito varias bibliotecas para agilizar las operaciones asíncronas. RxJava es la biblioteca más popular hoy en día para la programación reactiva y el diseño de una aplicación asíncrona.

Entonces, ¿por qué estoy escribiendo sobre la vieja escuela?

Looper, Handler, y HandlerThread son la forma de Android de resolver los problemas de la programación asíncrona. No son de la vieja escuela, sino una estructura ordenada sobre la que se construye un complejo marco de Android.

Para los desarrolladores nuevos, es muy recomendable comprender los principios detrás de ellos y los experimentados deben volver a visitar este tema para recordar los detalles menores.

También he creado un video tutorial para este tema, y recomiendo verlo. Haz clic aquí para verlo ahora.

Casos de uso:

  1. El hilo principal de Android se crea con Looper y Handlers. Por lo tanto, la comprensión de esto es esencial para crear una interfaz de usuario receptiva desbloqueada.
  2. Los desarrolladores que escriben bibliotecas no pueden permitirse el lujo de usar bibliotecas de terceros debido al tamaño de la biblioteca. Por lo tanto, para ellos, la mejor opción es utilizar el recurso disponible existente. Escribir una solución propia para ti no siempre puede obtener ese nivel de eficiencia y optimización.
  3. El mismo argumento también se puede hacer para empresas / individuos que envían SDK. Los clientes pueden tener implementaciones variadas, pero todos ellos compartirán las API comunes del marco de trabajo de Android.
  4. Comprenderlos por completo mejorará la capacidad de seguir las clases de paquetes y SDK de Android en general.

Comencemos la exploración / revisión con un cuestionario.

Espero que el lector tenga la comprensión básica de los hilos de Java. Si lo necesita, obtenga una visión general rápida de java Thread y Runnable.

¿Cuál es el problema con java thread?

Los subprocesos Java se usan una sola vez y mueren después de ejecutar su método run.

¿Podemos mejorarlo?

El hilo es una espada de doble filo. Podemos acelerar la ejecución distribuyendo las tareas entre subprocesos de ejecución, pero también podemos ralentizarla cuando los subprocesos están en exceso. La creación de hilos en sí misma es una sobrecarga. Por lo tanto, la mejor opción es tener un número óptimo de subprocesos y reutilizarlos para la ejecución de tareas.Modelo

para reutilización de roscas:

  1. El hilo se mantiene vivo, en un bucle a través de su método run().
  2. La tarea es ejecutada en serie por ese subproceso y se mantiene en una cola (MessageQueue).
  3. El hilo debe terminar cuando esté terminado.

¿Cuál es la forma de hacerlo de Android?

El modelo anterior se implementa en Android a través de Looper, Handler y HandlerThread. El Sistema se puede visualizar como un vehículo como en la portada del artículo.

  1. MessageQueue es una cola que tiene tareas llamadas mensajes que deben procesarse.
  2. Handler encuela la tarea en MessageQueue usando Looper y también las ejecuta cuando la tarea sale de MessageQueue.
  3. Looper es un trabajador que mantiene vivo un hilo, loops a través de MessageQueue y envía mensajes al handler correspondiente para procesar.
  4. Finalmente Thread se termina llamando al método quit() de Looper.

Un hilo puede tener solo un Looper único y puede tener muchos Manejadores únicos asociados a él.

Crear Looper y MessageQueue para un hilo:

Un hilo obtiene un Looper y MessageQueue llamando a Looper.prepare() después de su ejecución. Looper.prepare() identifica el hilo de llamada, crea un objeto Looper y MessageQueue y asocia el thread con ellos en la clase de almacenamiento ThreadLocal. Se debe llamar a Looper.loop()para iniciar el looper asociado. Del mismo modo, el looper debe terminar explícitamente a través de looper.quit().

class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here // this will run in non-ui/background thread } }; Looper.loop(); } }

Crear Manejador para un hilo:

A Handler se asocia implícitamente con el hilo que lo crea a través del hilo Looper, pero podemos vincularlo explícitamente a un hilo pasando el hilo looperen el constructor del Handler.

handler = new Handler() {@Overridepublic void handleMessage(Message msg) { // process incoming messages here // this will run in the thread, which instantiates it }};

El envío de mensajes a MessageQueue a través de Handler se puede hacer de dos modos:

  1. Message: Es una clase que define varios métodos útiles para tratar con datos de mensajes. Para enviar un objeto establecemos la variable obj.
Message msg = new Message();msg.obj = "Ali send message";handler.sendMessage(msg);

Descripción detallada de la clase Message se puede encontrar aquí: https://developer.android.com/reference/android/os/Message.html

Runnable: Un ejecutable también se puede publicar en MessageQueue. Ej: publicar y ejecutar una tarea en el hilo principal.

new Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() { // this will run in the main thread }});

En el ejemplo anterior, creamos un Handler y proporcionamos Looper asociado con el hilo principal. Esto asocia este controlador al hilo principal. Cuando publicamos el Runnable, se pone en cola en el MessageQueue del hilo principal y luego se ejecuta en el hilo principal.

Handler es capaz de manipular mensajes de una amplia variedad de maneras, que se pueden encontrar aquí: https://developer.android.com/reference/android/os/Handler.html

Crear un hilo propio y proporcionar Lopper y MessageQueue no es la forma correcta de lidiar con el problema. Por lo tanto, Android ha proporcionado HandlerThread(subclase de Thread) para agilizar el proceso. Internamente hace lo mismo que nosotros, pero de una manera sólida. Por lo tanto, siempre use HandlerThread.

Una de las formas de crear el HandlerThread es subclasarlo y la mayoría de las veces usará este método.

private class MyHandlerThread extends HandlerThread { Handler handler; public MyHandlerThread(String name) { super(name); } @Override protected void onLooperPrepared() { handler = new Handler(getLooper()) { @Override public void handleMessage(Message msg) { // process incoming messages here // this will run in non-ui/background thread } }; }}

Nota: Hemos creado una instancia del Controlador cuando se llama a onLooperPrepared(). Por lo tanto, que Handler se puede asociar con que Looper.

  1. Looper solo se prepara después de llamar a start() de HandlerThread, es decir, después de que el hilo se esté ejecutando.
  2. A Handler se puede asociar a HandlerThread, solo después de que se prepare Looper.

Otra forma de crear el HandlerThread:

HandlerThread handlerThread = new HandlerThread("MyHandlerThread");handlerThread.start();Handler handler = new Handler(handlerThread.getLooper());

Nota: HandlerThread necesita llamar a myHandlerThread.quit() para liberar los recursos y detener la ejecución del subproceso.

Sugeriría practicar los códigos anteriores, para que pueda comprender sus pequeños detalles.

He creado un proyecto de ejemplo para simulación de Oficina de Correos. La Oficina de Correos se basa en HandlerThread y los clientes se comunican con la ayuda de la Oficina de Correos. Una clase de Simulador crea pocos Bots de cliente y delega su comunicación a MainActivity, que la renderiza en una transmisión en vivo.

El enlace a este ejemplo

También he creado un video tutorial para este tema, y recomiendo verlo. Haz clic aquí para verlo ahora.

Además, seamos amigos en Twitter, Linkedin, Github y Facebook.

El aprendizaje es un viaje, ¡aprendamos juntos!

Deja una respuesta

Tu dirección de correo electrónico no será publicada.