2012-05-13 10 views
48

En mis proyectos estoy usando BroadcastReceiver s como una devolución de llamada de un hilo de larga ejecución (por ejemplo, notificar a la actividad que se terminó una descarga y enviar algunos datos de respuesta de un Trabajador Thread para que la actividad pueda mostrar el mensaje apropiado para el usuario ..). Para usar BroadcastReceiver s Tengo que tener cuidado de registrar y anular el registro del receptor de difusión cada vez que lo estoy usando y también tener que importar qué mensajes enviar esspecialy cuando estoy usando este método para más acciones diferentes (como descargar, hacer WebService llamadas, etc.). Y también para enviar objetos personalizados a través de la intención de Broadcast también necesito hacer los objetos Parcelable.Android BroadcastReceiver o método simple de devolución de llamada?

A diferencia de este enfoque, también he visto el enfoque de los métodos de devolución de llamada que parece ser más simple que el método que uso. Los métodos de devolución de llamada son simples Implementación de métodos de interfaz que se pueden usar para lograr el mismo efecto, como los mensajes de aplicación de BroadcastRecaiver. Este enfoque no necesita implementación Parcelable para devolver objetos complejos y no usa claves como BroadcastReceiver ... Creo que la parte mala es que necesito verificar el valor nulo del objeto de devolución de llamada antes de querer llamar a un método de devolución de llamada. y también para asegurarme de que estoy ejecutando el código de la implementación en el hilo de la interfaz de usuario para que pueda actualizar la interfaz de usuario sin errores.

Ok, espero que hayan entendido lo que quise decir :).

Ahora la pregunta es, ¿cree que el método de devolución de llamada es mejor (más ligero, más limpio, más rápido ...) que el enfoque BroadcastReceiver cuando se utiliza solo dentro de una sola aplicación? (Tenga en cuenta que no estoy usando Android Service para trabajos de fondo ... solo AsyncTask y Thread s)

¡Gracias!

Respuesta

78

Ésta es una pregunta muy interesante y me encontré con el mismo problema. En mi opinión, ambos mecanismos se pueden utilizar por completo y el enfoque correcto para su uso depende de su caso de uso. Aquí hay algunos puntos que deben tenerse en cuenta antes de tomar una decisión.

El uso de la devolución de llamada-mecanismo tiene algunas ventajas, pero también hay limitaciones:

PRO

  • Es simple y sencillo de implementar.
  • Obtiene seguridad de tipo entre los componentes que interactúan entre sí.
  • Puede devolver objetos arbitrarios.
  • Simplifica las pruebas ya que solo tiene que inyectar una devolución de llamada simulada (por ejemplo, generada a través de mockito o algo similar) en pruebas unitarias.

CONTRA

  • Tienes que cambiar al hilo principal con el fin de hacer manipulaciones de interfaz de usuario.
  • Solo puede tener una relación de 1 a 1. Una relación de 1 a n (patrón de observador) no es realizable sin más trabajo. En este caso, preferiría el mecanismo Observer/Observable de Android.
  • Como ya ha dicho, siempre debe verificar null antes de invocar las funciones de devolución de llamada si la devolución de llamada puede ser opcional.
  • Si su componente debe ofrecer un tipo de API de servicio con diferentes funciones de servicio y no desea tener una interfaz de devolución de llamada con solo algunas funciones genéricas de devolución de llamada, debe decidir si proporciona una interfaz de devolución de llamada especial para cada función de servicio o si proporciona una única interfaz de devolución de llamada con muchas funciones de devolución de llamada. En el caso posterior, todos los clientes de devolución de llamada utilizados para las llamadas de servicio a su API tienen que implementar la interfaz de devolución de llamada completa, aunque la mayoría de los cuerpos de método estarán vacíos. Puede solucionar esto implementando un stub con cuerpos vacíos y hacer que su cliente de devolución de llamada herede de ese stub, pero esto no es posible si ya hereda de otra clase base. Tal vez puedas usar algún tipo de devolución de llamada proxy dinámica (mira http://developer.android.com/reference/java/lang/reflect/Proxy.html), pero luego se vuelve realmente complejo y pensaría en usar otro mecanismo.
  • El cliente para las llamadas de devolución de llamada debe propagarse a través de varios métodos/componentes si la persona que llama no puede acceder directamente a él.

Algunos puntos relativos a la BroadcastReceiver -enfoque:

PRO

  • a lograr un acoplamiento débil entre los componentes.
  • Puede tener una relación 1-a-n (incluso de 1 a 0).
  • El método onReceive() siempre se ejecuta en el hilo principal.
  • Puede notificar componentes en toda su aplicación, por lo que los componentes de comunicación no tienen que "verse" entre ellos.

CONTRA

  • Este es un enfoque muy genérico, de modo de clasificación y unmarshalling de datos transportados por el Intent es una fuente de error adicional.
  • Tiene que hacer que las acciones de Intent sean únicas (por ejemplo, anteponiendo el nombre del paquete) si desea eliminar las correlaciones con otras aplicaciones, ya que su propósito original es realizar transmisiones entre aplicaciones.
  • Tienes que gestionar BroadcastReceiver -registro y anulación de registro. Si desea hacer esto de una manera más cómoda, puede implementar una anotación personalizada para anotar su Actividad con las acciones que deben registrarse e implementar una clase base Activity que realice el registro y anulación del registro con IntentFilter s en su onResume() resp. onPause() métodos.
  • Como ya ha dicho, los datos que se envían con Intent tienen que implementar la interfaz Parcelable, pero además hay una limitación de tamaño estricta y causará problemas de rendimiento si transporta una gran cantidad de datos con su Intent. Vea http://code.google.com/p/android/issues/detail?id=5878 para una discusión sobre eso. Entonces, si desea enviar imágenes, por ejemplo, tiene que almacenarlas temporalmente en un repositorio y enviar una ID o URL correspondiente para acceder a la imagen desde el receptor de su Intent que la borra del repositorio después de su uso. Esto conduce a más problemas si hay varios receptores (¿cuándo debería eliminarse la imagen del repositorio y quién debería hacer eso?).
  • Si usa este mecanismo de notificación en exceso, el flujo de control de su aplicación puede ocultarse y al depurarlo termina dibujando gráficos con secuencias de Intent para comprender qué ha desencadenado un error específico o por qué esta cadena de notificación se rompe en algún punto.

En mi opinión, incluso una aplicación móvil debe tener una base de arquitectura en al menos 2 capas: la capa UI y la capa central (con lógica comercial, etc.). En general, las tareas de ejecución prolongada se ejecutan en un hilo propio (tal vez a través de AsyncTask o HandlerThread si usa MessageQueue s) dentro de la capa central y la UI debe actualizarse una vez que esta tarea haya finalizado. En general, con las retrollamadas, logra un acoplamiento estrecho entre sus componentes, por lo que preferiría usar este enfoque solo dentro de una capa y no para la comunicación a través de los límites de la capa. Para la transmisión de mensajes entre UI y core-layer, usaría el enfoque BroadcastReceiver que le permite desacoplar su capa de interfaz de usuario de la capa lógica.

+0

He otorgado esto como una respuesta y le doy la recompensa porque es la respuesta más completa ... ¡Gracias a todos por sus ideas! – Cata

+0

Excelente respuesta. Soy un fanático del patrón de devolución de llamada/interfaz, pero a menudo heredo proyectos con un amplio uso del patrón de intención de transmisión y a menudo me pregunto si estoy yendo por el camino equivocado al respecto. Es bueno escuchar que realmente es una cuestión de preferencia de diseño en lugar de la mejor práctica. Me gusta la seguridad de tipo y la claridad de código ofrecida por las interfaces y probablemente me apegue a ellas por ahora –

+0

opinión muy interesante y detallada +1 – Jorgesys

6

No veo lo que gana usando BroadcastReceiver en su caso. Devolución de llamada o, mejor probablemente, Handlers sería la manera de hacerlo. BroadcastReceiver es bueno cuando no sabes quiénes son los suscriptores.

+0

Gracias por su respuesta, aunque voy a esperar un poco para obtener más respuestas .. – Cata

2

Se deben utilizar receptores de difusión Si necesita enviar transmisiones a través de aplicaciones mientras que las devoluciones de llamada (o controladores según lo sugerido por Alex) son mejores para usar en su situación.

Si desea utilizar otras que no sean estas dos, considere usar Observer (interfaz incluida en android) y delegue.

Para delegado, tenga en cuenta this SO post.

3

voy a añadir otra opción para los otros grandes respuestas que ha recibido ya ...

Usted no tiene que crear un receptor de radio para recibir Intentos. En el archivo de manifiesto de Android se puede registrar cualquier actividad para recibir las intenciones:

<activity android:name=".MyActivity"> 
     <intent-filter > 
       <action android:name="intent.you.want.to.receive" /> 
       <category android:name="android.intent.category.DEFAULT" /> 
     </intent-filter>  
.... 
</activity> 

A continuación, reemplazar el método onNewIntent(Intent) en su actividad para recibirlo.

Para enviar la intención, utilice el método Context.startActivity(Intent). Lo más probable es que desee agregar el indicador FLAG_ACTIVITY_SINGLE_TOP a su Intención para que no cree una nueva instancia de su actividad si ya se está ejecutando.

EDITAR: Me di cuenta de que se está ejecutando en una sola aplicación. Por lo tanto, una devolución de llamada simple es probablemente la mejor.La solución anterior funciona en una sola aplicación, pero es más adecuada para diferentes aplicaciones. Dejaré esto aquí en caso de que ayude a alguien. ¡Buena suerte!

+0

Extremidad excelente!Me gustaría agregar, sin embargo, que el mismo enfoque '' también se aplica a los servicios, si desea aislar implementaciones que no sean UI, en cuyo caso llamaría 'Context.startService (Intención) 'en cambio. Si su servicio objetivo se extiende ['IntentService'] (http://developer.android.com/reference/android/app/IntentService.html) tendrá una" cola de mensajes asíncrona "gratis, ya que' IntentService' solo ejecutar en un 'Intent' en el momento y el método' onHandleIntent' se ejecutará en un hilo de trabajo. – dbm

1

no está seguro de cuál es el objetivo, pero si desea mantener la misma idea de usar intendant y broadcastReceiver, y desea un mejor rendimiento y seguridad que los broadcastReceivers normales, puede probar esta demostración, disponible en la biblioteca de soporte de Android:

http://developer.android.com/resources/samples/Support4Demos/src/com/example/android/supportv4/content/LocalServiceBroadcaster.html

si no, siempre se puede utilizar AsyncTask, el servicio, los manipuladores, etc ...

Cuestiones relacionadas