Android: mensajes y eventos con Broadcasts

Última actualización: 26/07/2017

android

Un Broadcast Receiver puede verse como un listener que atiende a eventos del sistema, esto es, lanzados por el sistema operativo, o bien a eventos lanzados por aplicaciones. Además, el evento puede incluir información adicional en un Intent. Nos encontramos por tanto ante un mecanismo que nos permitirá integrar aplicaciones entre sí y/o con Android, pero también establecer un canal de comunicación interno entre componentes (activities, fragments…) de una misma app. En el presente tutorial veremos una introducción a las posibiliaddes que nos ofrece la utilización de este componente.

Atender un evento

En la documentación de la clase Intent se pueden ver los eventos lanzados por Android y que podemos recibir implementando un Broacast Receiver en nuestra aplicación. Para ello basta con heredar de la clase BroadcastReceiver. En el siguiente ejemplo se crea un Broadcast Receiver que será ejecutado cuando el teléfono realice una llamada. Para este evento en el intent se recibirá el número marcado.

package com.danielme.broadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;


public class OutgoinCallBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

        String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
        Toast.makeText(context, phoneNumber, Toast.LENGTH_LONG).show();
    }
}

Para que el Broadcast Receiver sea invocado debe «registrarse» en el sistema operativo. Este registro puede realizarse de dos formas en función del comportamiento que necesitemos:

Cursos aplicaciones móviles

  1. En el AndroidManifest.xml. Los Broadcast Receiver que se registren de esta forma son llamados siempre aunque la aplicación no esté en ejecución. La única restricción que se aplica es que por seguridad la aplicación debe haber sido ejecutada al menos una vez. Indicaremos la clase y las acciones que se atenderán (en este ejemplo concreto es necesario añadir un permiso):
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.danielme.broadcastreceiver" >
        <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> 
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <receiver android:name=".OutgoinCallBroadcastReceiver" >
                <intent-filter>
                    <action android:name="android.intent.action.NEW_OUTGOING_CALL" >
                    </action>
                </intent-filter>
            </receiver>
        </application>
    
    </manifest>
    
    
  2. De forma programática. El Broadcast Receiver se puede registrar directamente en el contexto de la aplicación de tal modo que esté activo mientras la aplicación esté en ejecución:
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
            getApplicationContext().registerReceiver(new OutgoinCallBroadcastReceiver(), filter);
    

    también puede ser asociado a una Activity en concreto:

            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
            registerReceiver(new OutgoinCallBroadcastReceiver(), filter);
    

    en este último caso es imprescindible «desregistrar» el Broadcast Receiver mediante el método unregisterReceiver antes de que la Activity sea destruída por Android ya que de lo contrario obtendremos el error has leaked IntentReceiver.

    Otra posibilidad es hacer que el Broadcast Receiver esté activo sólo mientras una Activity se esté mostrando en pantalla. En este caso, una posible estrategia a seguir es realizar el registro en el onResume y el «desregistro» en onPause.

     private OutgoinCallBroadcastReceiver outgoinCallBroadcastReceiver = new OutgoinCallBroadcastReceiver();
    
        @Override
        protected void onResume() {
            super.onResume();
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
            registerReceiver(outgoinCallBroadcastReceiver, filter);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            unregisterReceiver(outgoinCallBroadcastReceiver);
        }
    

    También se puede mantener la «escucha» del broadcast durante todo el ciclo de vida de la activity realizando el registro en el onCreate y el desregistro en el onDestroy.

Enviar un evento

Se puede enviar un Broadcast al sistema para que sea atendido por los Broadcast Receiver que hayan sido configurados para ello. Tendremos que invocar el método sendBroadcast con un Intent que tendrá el nombre del evento al que corresponde el Broadcast (el valor Action) y todos los parámetros que se quieran añadir.

Intent intent = new Intent();
intent.setAction("com.danielme.blog.ACTION_EVENTO");
sendBroadcast(intent);

Existe una versión del método sendBroadcast que permite especificar el permiso que deben tener las aplicaciones que quieran escuchar el Broadcast enviado. Por ejemplo:

sendBroadcast(intent, "com.danielme.blog.permission.EVENTO");

Este permiso que hemos «inventado» debe declarase en el AndroidManifest.xml de la aplicación que envía el Broadcast.

<permission android:name="com.danielme.blog.permission.EVENTO" 
        android:label="evento" 
        android:protectionLevel="dangerous"/>

Se solicitará la posesión de dicho permiso en el AndroidManifest.xml de las aplicaciones que deban escuchar nuestro mensaje de Broadcast

 <uses-permission android:name="com.danielme.blog.permission.EVENTO" />

Es muy recomendable utilizar este control de permisos siempre que sea posible si implementamos un mecanismo de broadcast que puede ser utilizado desde fuera de nuestra aplicación.

Eventos locales

Si el sistema de envío y recepción de eventos que estamos implementando sólo va a ser usado dentro de una misma aplicación, es más eficiente utilizar broadcasts locales con la clase LocalBroadcastManager, disponible en la librería de compatibilidad v4. Los eventos que lancemos con este mecanismo sólo pueden ser recibidos dentro de la propia aplicación.

Nota: Los broadcast locales no pueden ser registrados en el Manifest (nunca se invocarán).

El uso de estos broadcasts es análogo al que hemos visto anteriormente para los broadcasts globales, tan sólo tendremos que utilizar los métodos estáticos sendBroadcast, registerReceiver y unregisterReceiver.

A continuación se muestra un ejemplo real extraído de la versión 2.0 de Muspy for Android.

  private void notifyResult() {
    Intent intent = new Intent();
    intent.setAction(BROADCAST_ACTION_ARTIST);
    intent.putExtra(ARTIST_INTENT, artist);
    LocalBroadcastManager.getInstance(ArtistDetailActivity.this).sendBroadcast(intent);
  }
    @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ((MuspyApplication) getContext().getApplicationContext()).getApplicationDaggerComponent()
        .inject(this);

    artistBroadcastReceiver = new MyArtistBroadcastReceiver();
    IntentFilter filter = new IntentFilter();
    filter.addAction(ArtistDetailActivity.BROADCAST_ACTION_ARTIST);
    //broadcast is always listening if the Activity exists
    LocalBroadcastManager.getInstance(getActivity()).registerReceiver(artistBroadcastReceiver,
        filter);
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(artistBroadcastReceiver);
  }
Buses de eventos

Una alternativa a la utilización de broadcasts locales, y que recomiendo encarecidamente, son los buses de eventos implementados por las herramientas Otto y EventBus. Estos buses están diseñados para facilitar la comunicación de forma sencilla y eficiente entre distintos componentes (Activities, Fragments, Services) evitándose el «acoplamiento» y dependencias entre ellos . Aunque esto mismo podemos conseguirlo utilizando broadcasts locales, con las herramientas indicadas el código resultante es más sencillo y claro, y además con EventBus la recepción de los eventos se puede realizar de forma transparente y automática en el main thread o en otro hilo, entre otras opciones.

Proyecto de ejemplo

Para este tutorial no se proporciona un proyecto de ejemplo específico, pero se puede ver el uso de broadcasts en el ejemplo del tutorial Android: Servicio periódico con inicio automático y en el código de Muspy for Android.

Master Pyhton, Java, Scala or Ruby

3 comentarios sobre “Android: mensajes y eventos con Broadcasts

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.