¿Cuál es el propósito de Looper y cómo usarlo?
Soy nuevo en android. Quiero saber qué Looper
hace la clase y también cómo usarla. He leído la documentación de la clase Android Looper pero no puedo entenderla completamente. Lo he visto en muchos lugares pero no puedo entender su propósito. ¿Alguien puede ayudarme definiendo el propósito Looper
y también dando un ejemplo simple si es posible?
¿Qué es Looper?
Looper es una clase que se utiliza para ejecutar mensajes (Runnables) en una cola. Los subprocesos normales no tienen dicha cola, por ejemplo, los subprocesos simples no tienen ninguna cola. Se ejecuta una vez y una vez finalizada la ejecución del método, el hilo no ejecutará otro Mensaje (Ejecutable).
¿Dónde podemos usar la clase Looper?
Si alguien quiere ejecutar varios mensajes (Runnables), entonces 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 colocar los archivos que se descargarán en la cola.
¿Cómo funciona?
Existe un prepare()
método para preparar el Looper. Luego puede usar loop()
el método 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 mediante 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();
}
}
Puede comprender mejor qué es Looper en el contexto del marco GUI. Looper está hecho para hacer 2 cosas.
Looper transforma un hilo normal en algo que se ejecuta continuamente hasta que se ejecuta la aplicación de Android.
Looper proporciona una cola donde se ponen en cola los trabajos por realizar.
Como sabrá, cuando se inicia una aplicación, el sistema crea un hilo de ejecución para la aplicación, llamado "principal", y las aplicaciones de Android normalmente se ejecutan completamente en un solo hilo, de forma predeterminada, el "hilo principal". Pero el hilo principal no es un hilo especial y secreto . Es simplemente un hilo normal similar a uno que puedes crear con new Thread()
, lo que significa que termina cuando run()
regresa su método. Piense 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 las aplicaciones 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 inicia su aplicación y dibuja toda la UI. Entonces la primera pantalla se muestra a los usuarios. ¿Ahora que? ¿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 finaliza su trabajo inicial para mostrar la primera pantalla y duerme. Se despierta, lo que significa interrumpido, cuando se le solicita un nuevo trabajo. Hasta ahora todo bien, pero en este momento necesitamos una estructura de datos similar a una cola para realizar múltiples trabajos. Piense en un caso en el que un usuario toca la pantalla en serie y una tarea tarda más en finalizar. Por lo tanto, necesitamos tener una estructura de datos para mantener los trabajos que deben realizarse primero en entrar, primero en salir. Además, como puede imaginar, implementar un subproceso que siempre se ejecuta y procesa el trabajo cuando llega utilizando la interrupción no es fácil y conduce a un código complejo y, a menudo, imposible de mantener. Preferimos crear un nuevo mecanismo para tal propósito, 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", y Looper es una clase "utilizada para ejecutar un bucle de mensajes para un subproceso". Ahora puedes entender lo que significa.
Para aclarar las cosas, revisemos 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 normal en algo que necesitamos.
public final class ActivityThread {
...
public static void main(String[] args) {
...
Looper.prepareMainLooper();
Looper.loop();
...
}
}
y Looper.loop()
el método se repite infinitamente y retira de la cola un mensaje y procesa uno a la vez:
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 creada para abordar un problema que ocurre en el marco de la GUI. Pero este tipo de necesidad también puede ocurrir en otras situaciones. En realidad, es un patrón bastante famoso para aplicaciones de subprocesos múltiples, 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 todos los marcos de GUI pueden necesitar algo similar. También puede encontrar casi el mismo mecanismo en el marco Java Swing.
Looper permite que las tareas se ejecuten secuencialmente en un solo hilo. Y el controlador define aquellas tareas que debemos ejecutar. Es un escenario típico que intento 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 algunos otros subprocesos (por ejemplo, el subproceso de la interfaz de usuario) para publicar la tarea en Looper para ejecutarla.
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.