handlerthread example app android multithreading android-looper

example - looper android apk



¿Cuál es el propósito de Looper y cómo usarlo? (9)

Android Looper es un contenedor para adjuntar MessageQueue a Thread y administra el procesamiento de la cola. Parece muy críptico en la documentación de Android y muchas veces podemos enfrentar problemas de acceso a la interfaz de usuario relacionados con Looper . Si no entendemos lo básico, se vuelve muy difícil de manejar.

Aquí hay un article que explica el ciclo de vida de Looper , cómo usarlo y el uso de Looper en Handler

Looper = Thread + MessageQueue

Soy nuevo en android. Quiero saber qué hace la clase Looper y también cómo usarla. He leído la documentación de la clase de Android Looper pero no puedo entenderla completamente. Lo he visto en muchos lugares pero no puedo entender su propósito. ¿Puede alguien ayudarme definiendo el propósito de Looper y también dando un ejemplo simple si es posible?


El manejo de varios elementos de bajada o carga en un Service es un mejor ejemplo.

Handler AsnycTask y AsnycTask se utilizan a menudo para propagar eventos / mensajes entre la interfaz de usuario (subproceso) y un subproceso de trabajo o para retrasar las acciones. Así que están más relacionados con la interfaz de usuario.

Un Looper maneja las tareas ( Runnables, Futures ) en una cola relacionada con un subproceso en segundo plano, incluso sin interacción del usuario o una IU mostrada (la aplicación descarga un archivo en segundo plano durante una llamada).


Esta respuesta no tiene nada que ver con la pregunta, pero el uso de looper y la forma en que las personas crearon el manejador y el looper en TODAS las respuestas aquí son simplemente una mala práctica (aunque algunas explicaciones son correctas), debo publicar esto:

HandlerThread thread = new HandlerThread(threadName); thread.start(); Looper looper = thread.getLooper(); Handler myHandler = new Handler(looper);

y para una implementación completa.


La vida útil del java El Thread finaliza después de completar el método run() . El mismo hilo no puede ser iniciado de nuevo.

Looper transforma el Thread normal en un bucle de mensaje. Los métodos clave de Looper son:

void prepare ()

Inicialice el hilo actual como un looper. Esto le da la oportunidad de crear controladores que luego hacen referencia a este looper, antes de iniciar realmente el bucle. Asegúrese de llamar a loop () después de llamar a este método, y finalícelo llamando a quit ().

void loop ()

Ejecutar la cola de mensajes en este hilo. Asegúrese de llamar a quit () para finalizar el ciclo.

void quit()

Sale del looper.

Hace que el método loop () termine sin procesar más mensajes en la cola de mensajes.

Este artículo de Mindorks por Janishar explica los conceptos centrales de manera agradable.

Looper está asociado con un hilo. Si necesita Looper en el hilo de la IU, Looper.getMainLooper() devolverá el hilo asociado.

Necesitas que Looper esté asociado con un Handler .

Looper , Handler y HandlerThread son la forma de Android de resolver los problemas de la programación asíncrona.

Una vez que tenga Handler , puede llamar debajo de las API.

post (Runnable r)

Hace que el Runnable r se agregue a la cola de mensajes. El ejecutable se ejecutará en el subproceso al que se adjunta este controlador.

boolean sendMessage (Message msg)

Inserta un mensaje en el final de la cola de mensajes después de todos los mensajes pendientes antes de la hora actual. Se recibirá en handleMessage (Mensaje), en el hilo adjunto a este controlador.

HandlerThread es una clase útil para iniciar un nuevo hilo que tiene un looper. El looper se puede usar para crear clases de manejador.

En algunos casos, no puede ejecutar tareas Runnable en el hilo de la interfaz de usuario. Ej. Operaciones de red: envíe un mensaje en un socket, abra una URL y obtenga contenido leyendo InputStream

En estos casos, HandlerThread es útil. Puede obtener el objeto Looper en HandlerThread y crear un Handler en HandlerThread lugar de en el hilo principal.

El código HandlerThread será así:

@Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }

Consulte la siguiente publicación para el código de ejemplo:

Android: tostadas en un hilo


Looper permite que las tareas se ejecuten secuencialmente en un solo hilo. Y el manejador define aquellas tareas que necesitamos ejecutar. Es un escenario típico que estoy tratando de ilustrar en este ejemplo:

class SampleLooper extends Thread { @Override public void run() { try { // preparing a looper on current thread // the current thread is being detected implicitly Looper.prepare(); // now, the handler will automatically bind to the // Looper that is attached to the current thread // You don''t need to specify the Looper explicitly handler = new Handler(); // After the following line the thread will start // running the message loop and will not normally // exit the loop unless a problem happens or you // quit() the looper (see below) Looper.loop(); } catch (Throwable t) { Log.e(TAG, "halted due to an error", t); } } }

Ahora podemos usar el controlador en otros subprocesos (por ejemplo, el subproceso de la interfaz de usuario) para publicar la tarea en Looper para ejecutar.

handler.post(new Runnable() { public void run() { //This will be executed on thread using Looper. } });

En el hilo de la interfaz de usuario tenemos un Looper implícito que nos permite manejar los mensajes en el hilo de la interfaz de usuario.


Puede comprender mejor qué es Looper en el contexto del marco de GUI. Looper está hecho para hacer 2 cosas.

1) Looper transforma un subproceso normal , que termina cuando su método run () regresa, en algo que se ejecuta continuamente hasta que se ejecuta la aplicación de Android , lo cual es necesario en el marco de la GUI (técnicamente, aún termina cuando el método run () regresa. aclarar lo que quiero decir en la parte inferior).

2) Looper proporciona una cola donde se ponen en cola los trabajos a realizar, que también se necesitan en el marco de GUI.

Como sabrá, cuando se inicia una aplicación, el sistema crea un subproceso de ejecución para la aplicación, llamado "principal", y las aplicaciones de Android normalmente se ejecutan completamente en un solo subproceso, de forma predeterminada, el "subproceso principal". Pero el hilo principal no es un hilo secreto, especial . Es solo un hilo normal similar a los hilos que creas con el new Thread() código new Thread() , lo que significa que termina cuando su método run () regresa. Piensa en el siguiente ejemplo.

public class HelloRunnable implements Runnable { public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new Thread(new HelloRunnable())).start(); } }

Ahora, apliquemos este principio simple a la aplicación de Android. ¿Qué pasaría si una aplicación de Android se ejecuta en un hilo normal? Un hilo llamado "principal" o "UI" o lo que sea que inicie su aplicación, y dibuja toda la IU. Así, la primera pantalla se muestra a los usuarios. ¿Y ahora qué? El hilo principal termina? No, no debería. Debería esperar hasta que los usuarios hagan algo, ¿verdad? Pero, ¿cómo podemos lograr este comportamiento? Bueno, podemos probar con Object.wait() o Thread.sleep() . Por ejemplo, el hilo principal termina su trabajo inicial para mostrar la primera pantalla y se pone en espera. Se despierta, lo que significa que se interrumpe, cuando se busca un nuevo trabajo por hacer. Hasta ahora todo bien, pero en este momento necesitamos una estructura de datos similar a una cola para mantener varios trabajos. Piense en un caso cuando un usuario toca la pantalla en serie y una tarea tarda más tiempo en finalizar. Por lo tanto, necesitamos tener una estructura de datos para mantener los trabajos que se realizarán de la manera en que el primero en ser el primero en salir. Además, puede imaginar que la implementación de un subproceso que siempre se ejecuta y procesa cuando llega una interrupción no es fácil, y conduce a un código complejo que a menudo no se puede mantener. Preferimos crear un nuevo mecanismo para tal fin, y de eso se trata Looper . El documento oficial de la clase Looper dice: "Los subprocesos por defecto no tienen un bucle de mensajes asociado a ellos", y Looper es una clase "usada para ejecutar un bucle de mensajes para un hilo". Ahora puedes entender lo que significa.

Para aclarar las cosas, verifiquemos el código donde se transforma el hilo principal. Todo sucede en la clase ActivityThread . En su método main (), puede encontrar el siguiente código, que convierte un hilo principal normal en algo que necesitamos.

public final class ActivityThread { ... public static void main(String[] args) { ... Looper.prepareMainLooper(); Looper.loop(); ... } }

y el bucle del método Looper.loop() es infinito, saca de la cola un mensaje y lo procesa uno por uno:

public static void loop() { ... for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } ... msg.target.dispatchMessage(msg); ... } }

Entonces, básicamente, Looper es una clase que está hecha para abordar un problema que ocurre en el marco de GUI. Pero este tipo de necesidades también pueden ocurrir en otras situaciones. En realidad, es un patrón bastante famoso para la aplicación de varios subprocesos, y puede aprender más sobre él en " Programación concurrente en Java " de Doug Lea (Especialmente, el capítulo 4.1.4 "Subprocesos de trabajo" sería útil). Además, puede imaginar que este tipo de mecanismo no es único en el marco de Android, pero todo el marco de GUI puede necesitar algo similar a esto. Puedes encontrar casi el mismo mecanismo en el marco de Java Swing.


Un Looper tiene un MessageQueue synchronized que se utiliza para procesar los mensajes colocados en la cola.

Implementa un patrón de almacenamiento específico de Thread .

Solo un Looper por Thread . Los métodos clave incluyen prepare() , loop() y quit() .

prepare() inicializa el Thread actual como un Looper . prepare() es un método static que utiliza la clase ThreadLocal como se muestra a continuación.

public static void prepare(){ ... sThreadLocal.set (new Looper()); }

  1. prepare() debe llamarse explícitamente antes de ejecutar el bucle de eventos.
  2. loop() ejecuta el bucle de eventos que espera que los mensajes lleguen a la cola de mensajes de un subproceso específico. Una vez que se recibe el siguiente Mensaje, el método loop() envía el Mensaje a su controlador de destino
  3. quit() cierra el bucle de eventos. No termina el bucle, sino que encola un mensaje especial

Looper se puede programar en un Thread través de varios pasos

  1. Extender Thread

  2. Llame a Looper.prepare() para inicializar el subproceso como un Looper

  3. Cree uno o más Handler para procesar los mensajes entrantes

  4. Llame a Looper.loop() para procesar los mensajes hasta que se Looper.loop() al bucle que quit() .

Looper es una clase que convierte un subproceso en un subproceso de la tubería y el Handler le proporciona un mecanismo para insertar tareas desde otros subprocesos.

Por lo tanto, un PipeLine Thread es un subproceso que puede aceptar más tareas de otros subprocesos a través de un Handler .

El Looper se llama así porque implementa el bucle: toma la siguiente tarea, la ejecuta, luego toma la siguiente y así sucesivamente. El controlador se denomina controlador porque se usa para manejar o aceptar la siguiente tarea cada vez que se realiza desde cualquier otro subproceso y se pasa a Looper (Thread o PipeLine Thread).

El ejemplo perfecto de un Looper and Handler o PipeLine Thread es descargar más de una imagen o subirlas a un servidor (Http) una por una en un solo hilo en lugar de comenzar un nuevo Thread para cada llamada de red en segundo plano.

Lea más aquí sobre Looper y Handler y la definición de Pipeline Thread:

Android Guts: Introducción a Loopers y Handlers


¿Qué es Looper?

Looper es una clase que se utiliza para ejecutar los mensajes (Runnables) en una cola. Los subprocesos normales no tienen esa cola, por ejemplo, el subproceso simple no tiene ninguna cola. Se ejecuta una vez y una vez que finaliza la ejecución del método, el subproceso no ejecutará otro mensaje (ejecutable).

¿Dónde podemos usar la clase Looper?

Si alguien quiere ejecutar varios mensajes (Runnables), debe usar la clase Looper, que es responsable de crear una cola en el hilo. Por ejemplo, mientras escribimos una aplicación que descarga archivos de Internet, podemos usar la clase Looper para poner los archivos a descargar en la cola.

¿Cómo funciona?

Hay un método de prepare() para preparar el Looper. Luego puede usar el método loop() para crear un bucle de mensajes en el hilo actual y ahora su Looper está listo para ejecutar las solicitudes en la cola hasta que salga del bucle.

Aquí está el código por el cual puedes preparar el Looper.

class LooperThread extends Thread { public Handler mHandler; @Override public void run() { Looper.prepare(); mHandler = new Handler() { @Override public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }