android - programacion - Actualización de GUI: runnables vs mensajes
manual de android en pdf (4)
Para actualizar la GUI desde otros hilos, básicamente hay dos enfoques principales:
Use java.lang.Runnable con cualquiera de estos métodos:
Activity.runOnUiThread(Runnable) View.post(Runnable) View.postDelayed(Runnable, long) Handler.post(Runnable)
Use android.os.Message:
Handler.sendMessage(Message) / Handler.handleMessage(Message)
También puede usar AsyncTask, pero mi pregunta está más centrada en el caso de uso de actualizar un componente muy simple. Veamos cómo se haría usando ambos enfoques:
Usando Runnables:
TextViev tv = ...; final String data = "hello"; Runnable r = new Runnable() { @Override public void run(){ tv.setText(data); } }; //Now call Activity.runOnUiThread(r) or handler.post(r), ...
Usando mensajes:
Message m = handler.obtainMessage(UPDATE_TEXT_VIEW, "hello"); handler.sendMessage(m); //Now on handler implementation: @Override public void handleMessage(Message msg) { if(msg.what == UPDATE_TEXT_VIEW){ String s = (String) msg.obj; tv.setText(data); } ... //other IFs? }
En mi humilde opinión, los mensajes no son el camino a seguir porque:
- No es fácil de entender para los nuevos programadores que no son Android (los enganches del manejador a su hilo durante la construcción).
- La carga útil del objeto debe ser Parcellable si el mensaje cruza los límites del proceso.
- Los mensajes se vuelven a usar (¿son propensos a errores si no se limpian adecuadamente?)
- El controlador tiene un doble rol (envía mensajes, pero también los maneja)
- Los atributos del mensaje son públicos, pero también ofrecen getter / setter.
Por otro lado, Runnables sigue el conocido patrón de comandos, y son más amigables con los programadores y legibles.
¿Cuáles son las ventajas de usar Messages over Runnables? ¿Los mensajes están en segundo plano en la programación de Android moderna? ¿Hay algo que puedas hacer con los mensajes que no se pueden hacer con ejecutables?
Gracias por adelantado.
Diría que hay poca diferencia entre usar un Message
vs un Runnable
. En general, se reducirá a las preferencias personales. ¿Por qué? Al mirar el código fuente, verá que publicar un Runnable
usa el mismo mecanismo de mensajería. Simplemente conecta Runnable
a un Message
y lo envía.
4.4.2 Código fuente
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
Ref: Grep Code - Handler
Prefiero Runnable
al Message
. Creo que el código que usa Runnable
es mucho más claro que Message
, porque el código de manejo de eventos está muy cerca del evento. Además, puede evitar la sobrecarga de definir constantes e intercambiar casos.
Y no creo que el uso de Runnable
viole la encapsulación. Puede extraer el código en Runnable.run()
en otro método en la clase externa, por ejemplo on...Event()
, o incluso envolverlo en un objeto EventHandler
. Ambas formas son mucho más claras que el uso de Message
, especialmente cuando se necesitan referencias de tienda en Message
, porque el uso de Runnable
evita msg.obj
. Y el campo sin nombre msg.obj
también es propenso a errores y, a veces, ineficiente de entender.
Y Runnable
también puede reutilizarse almacenándolo como un campo.
Handler
interfaz del Handler
proporciona mucha más funcionalidad que runOnUiThread()
, de acuerdo con los documentos:
Hay dos usos principales para un Manejador:
(1) para programar mensajes y ejecutables que se ejecutarán como un punto en el futuro
(2) para poner en cola una acción que se realizará en un hilo diferente al suyo.
runOnUiThread
solo hace un subconjunto de (2). es decir, "poner en cola una acción que se realizará en el hilo de UI "
Así que IMO a menos que necesite esas características adicionales runOnUiThread
es suficiente y preferida.
Messages
se pueden reutilizar, por lo que se generan menos objetos creados y menos GC. También terminas con menos clases y tipos anónimos.
Una gran ventaja es que una clase que envía un Message
a un Handler
no necesita saber nada sobre la implementación de ese Message
. Eso puede ayudar en la encapsulación dependiendo de dónde se usa.
Por último, considere la diferencia de limpieza entre
mHandler.obtainMessage(DO_STUFF, foo).sendToTarget();
vs
final Foo tempFoo = foo;
mHandler.post(new Runnable(){
@Override
public void run(){
doStuff(tempFoo);
}
};
Si tiene varios lugares en los que debería hacer doStuff()
, el primero es MUCHO más legible y tendrá menos duplicación de código.