Receptores de transmisión para principiantes

Supongamos que tiene una aplicación que depende de una conexión a Internet estable. Desea que su aplicación reciba una notificación cuando cambie la conexión a Internet. ¿Cómo haces eso? Una posible solución sería un servicio que compruebe siempre la conexión a Internet. Esta implementación es mala por varias razones, por lo que ni siquiera la consideraremos. La solución a este problema es un receptor de transmisión y escuchará los cambios que le indique. Un receptor de transmisión siempre recibirá una notificación de una transmisión, independientemente del estado de su solicitud. No importa si su aplicación se está ejecutando actualmente, en segundo plano o no se está ejecutando en absoluto.

Antecedentes

Los receptores de transmisión son componentes en su aplicación de Android que escuchan los mensajes (o eventos) de transmisión de diferentes medios:

  • De otras aplicaciones
  • Del propio sistema
  • De tu aplicación

Es decir, que se invocan cuando se ha producido una determinada acción que han sido programados para escuchar (es decir, una transmisión).

Una transmisión es simplemente un mensaje envuelto dentro de un objeto Intent. Una transmisión puede ser implícita o explícita.

  • Una transmisión implícita es aquella que no se dirige específicamente a su aplicación, por lo que no es exclusiva de su aplicación. Para registrarse para uno, debe usar un IntentFilter y declararlo en su manifiesto. Debe hacer todo esto porque el sistema operativo Android revisa todos los filtros de intención declarados en su manifiesto y ve si hay una coincidencia. Debido a este comportamiento, las difusiones implícitas no tienen un atributo de destino. Un ejemplo de difusión implícita sería una acción de un mensaje SMS entrante.
  • Una transmisión explícita es aquella que está dirigida específicamente a su aplicación en un componente que se conoce de antemano. Esto sucede debido al atributo de destino que contiene el nombre del paquete de la aplicación o el nombre de una clase de componente.

Hay dos formas de declarar un receptor:

  1. Declarando uno en su archivo AndroidManifest.xml con la etiqueta (también llamada estática)

Notará que el receptor de transmisión declarado anteriormente tiene una propiedad de exported = ”true” . Este atributo le dice al receptor que puede recibir transmisiones desde fuera del alcance de la aplicación.

2. O dinámicamente registrando una instancia con registerReceiver (lo que se conoce como contexto registrado)

public abstract Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter);

Implementación

Para crear su propio receptor de transmisión, primero debe extender la clase principal BroadcastReceiver y anular el método obligatorio, onReceive:

public void onReceive(Context context, Intent intent) { //Implement your logic here }

Poniendo todo junto produce:

public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { StringBuilder sb = new StringBuilder(); sb.append("Action: " + intent.getAction() + "\n"); sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n"); String log = sb.toString(); Toast.makeText(context, log, Toast.LENGTH_LONG).show(); } }
⚠️El método onReceive se ejecuta en el hilo principal, y debido a esto, su ejecución debe ser breve.

Si se ejecuta un proceso largo, el sistema puede detener el proceso después de que regrese el método. Para evitar esto, considere usar goAsync o programar un trabajo. Puede leer más sobre la programación de un trabajo al final de este artículo.

Ejemplo de registro dinámico

Para registrar un receptor con un contexto, primero debe crear una instancia de su receptor de transmisión:

BroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();

Luego, puede registrarlo según el contexto específico que desee:

IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); this.registerReceiver(myBroadcastReceiver, filter);

No olvide cancelar el registro de su receptor de transmisión cuando ya no lo necesite

@Override protected void onStop() { super.onStop(); unregisterReceiver(myBroadcastReceiver); }

Transmitiendo un evento

El objetivo detrás de la transmisión de mensajes desde su aplicación es permitir que su aplicación responda a los eventos a medida que ocurren dentro de ella. Piense en un escenario en el que en una parte del código, el usuario realiza una determinada acción y, por eso, desea ejecutar alguna otra lógica que tiene en un lugar diferente.

Hay tres formas de enviar transmisiones:

  1. El sendOrderedBroadcast, asegúrese de enviar transmisiones a un solo receptor a la vez. Cada transmisión puede, a su vez, pasar datos al siguiente o detener la propagación de la transmisión a los receptores siguientes.
  2. El sendBroadcast es similar al método mencionado anteriormente, con una diferencia. Todos los receptores de difusión reciben el mensaje y no dependen unos de otros.
  3. El método LocalBroadcastManager.sendBroadcast solo envía transmisiones a los receptores definidos dentro de su aplicación y no excede el alcance de su aplicación. Ejemplo de envío de una transmisión personalizada

//giphy.com/gifs/23gUJhHyWkXEwl7UYV/html5

Problemas y cosas a las que prestar atención

  • No envíe datos confidenciales a través de una transmisión implícita, porque cualquier aplicación que los escuche los recibirá. Puede evitar esto especificando un paquete o adjuntando un permiso a la transmisión.
  • No inicie actividades desde una transmisión recibida, ya que falta la experiencia del usuario. Elija mostrar una notificación en su lugar.

Los siguientes puntos se refieren a cambios en los receptores de transmisión relevantes para cada versión del sistema operativo Android (a partir de la 7.0). Para cada versión, se han producido ciertas limitaciones y el comportamiento también ha cambiado. Tenga en cuenta estas limitaciones cuando piense en utilizar un receptor de transmisión.

  • 7.0 y versiones posteriores ( nivel de API 24) : se han deshabilitado dos transmisiones del sistema, Action_New_Picture y Action_New_Video (pero se recuperaron en Android O para receptores registrados)
  • 8.0 y versiones posteriores (nivel de API 26) : la mayoría de las transmisiones implícitas deben registrarse de forma dinámica y no estática (en su manifiesto). Puede encontrar las transmisiones que se incluyeron en la lista blanca en este enlace.
  • 9.0 y versiones posteriores (API nivel 28) : se recibe menos información sobre la transmisión del sistema Wi-Fi y Network_State_Changed_Action.

Los cambios en Android O son los que debes conocer. La razón por la que se realizaron estos cambios fue porque provocaban problemas de rendimiento, agotamiento de la batería y daños en la experiencia del usuario. Esto sucedió porque muchas aplicaciones (incluso las que no se están ejecutando actualmente) estaban escuchando un cambio en todo el sistema y cuando ocurrió ese cambio, se produjo el caos. Imagínese que todas las aplicaciones registradas en la acción cobraron vida para comprobar si tenían que hacer algo debido a la transmisión. Tenga en cuenta algo como el estado de Wi-Fi, que cambia con frecuencia, y comenzará a comprender por qué se produjeron estos cambios.

Alternativas a los receptores de radiodifusión

Para que sea más fácil navegar por todas estas restricciones, a continuación se muestra un desglose de otros componentes que puede usar en ausencia de un receptor de transmisión. Cada uno tiene una responsabilidad y un caso de uso diferentes, así que intente determinar cuál se adapta a sus necesidades.

  • LocalBroadcastManager : como mencioné anteriormente, esto es válido solo para transmisiones dentro de su aplicación
  • Programación de un trabajo : se puede ejecutar un trabajo según la señal o el disparador recibido, por lo que es posible que la transmisión que estaba escuchando pueda ser reemplazada por un trabajo. Además, elJobScheduler garantizará la finalización de su trabajo, pero tendrá en cuenta varios factores del sistema (tiempo y condiciones) para determinar cuándo debe ejecutarse. Al crear un trabajo, anulará un método llamado onStartJob . Este método se ejecuta en el hilo principal, así que asegúrese de que finalice su trabajo en un período de tiempo limitado. Si necesita realizar una lógica compleja, considere iniciar una tarea en segundo plano. Además, el valor de retorno de este método es un booleano, donde verdadero indica que aún se están realizando ciertas acciones y falso significa que el trabajo está hecho.

Si desea experimentar de primera mano la alegría y la maravilla que son los receptores de transmisión, puede seguir estos enlaces a los repositorios que he configurado:

  1. Difusión personalizada (con declaración de manifiesto)
  2. Registro de transmisión (sin declarar una en el manifiesto)
  3. LocalBroadcastManager

Transmitir.