¿Cómo verificar si Receiver está registrado en Android?

Respuestas:

68

No estoy seguro de que la API proporcione directamente una API, si considera este hilo :

Me preguntaba lo mismo.
En mi caso, tengo una BroadcastReceiverimplementación que llama Context#unregisterReceiver(BroadcastReceiver)pasarse a sí mismo como argumento después de manejar la intención que recibe.
Existe una pequeña posibilidad de que el onReceive(Context, Intent)método del receptor se llame más de una vez, ya que está registrado con múltiples IntentFilters, creando la posibilidad de que IllegalArgumentExceptionse lo arroje Context#unregisterReceiver(BroadcastReceiver).

En mi caso, puedo almacenar un miembro privado sincronizado para verificar antes de llamar Context#unregisterReceiver(BroadcastReceiver), pero sería mucho más limpio si la API proporcionara un método de verificación.

VonC
fuente
313

No hay una función API para verificar si un receptor está registrado. La solución es poner su código en untry catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}
Daniel Velkov
fuente
83
eso es un fastidio ... :(
Sander Versluys
44
Lo curioso es que no detecta el error de esta llamada a BroadcastReceiver para registerReceiver (mReceiver, filter1);
JPM
1
@JPM Sí lo es. Iba a almacenar una instancia de mi receptor y marcaría para cancelar el registro si no es así null. Pero como usted señaló, voy con try catch. Ridículo.
99
Vota a Android por no crear una API para eso. +1 a usted por proporcionar una solución de trabajo :)
Denys Vitali
1
¿Que es mejor? usando esto o usando una variable booleana como bandera?
DAVIDBALAS1
34

solución más simple

en receptor:

public class MyReceiver extends BroadcastReceiver {   
    public boolean isRegistered;

    /**
    * register receiver
    * @param context - Context
    * @param filter - Intent Filter
    * @return see Context.registerReceiver(BroadcastReceiver,IntentFilter)
    */
    public Intent register(Context context, IntentFilter filter) {
        try {
              // ceph3us note:
              // here I propose to create 
              // a isRegistered(Contex) method 
              // as you can register receiver on different context  
              // so you need to match against the same one :) 
              // example  by storing a list of weak references  
              // see LoadedApk.class - receiver dispatcher 
              // its and ArrayMap there for example 
              return !isRegistered 
                     ? context.registerReceiver(this, filter) 
                     : null;
            } finally {
               isRegistered = true;
            }
    }

    /**
     * unregister received
     * @param context - context
     * @return true if was registered else false
     */
     public boolean unregister(Context context) {
         // additional work match on context before unregister
         // eg store weak ref in register then compare in unregister 
         // if match same instance
         return isRegistered 
                    && unregisterInternal(context);
     }

     private boolean unregisterInternal(Context context) {
         context.unregisterReceiver(this); 
         isRegistered = false;
         return true;
     }

    // rest implementation  here 
    // or make this an abstract class as template :)
    ...
}

en codigo:

MyReceiver myReceiver = new MyReceiver();
myReceiver.register(Context, IntentFilter); // register 
myReceiver.unregister(Context); // unregister 

anuncio 1

-- en respuesta a:

Esto realmente no es tan elegante porque debes recordar configurar el indicador isRegistered después de registrarte. - Stealth Rabbi

- Método agregado de "forma más elegante" en el receptor para registrar y establecer la bandera

esto no funcionará si reinicia el dispositivo o si el sistema operativo eliminó su aplicación. - amin hace 6 horas

@amin: vea la vida útil del código en el receptor registrado (no el sistema registrado por entrada de manifiesto)

ceph3us
fuente
2
Esta es realmente una solución elegante. FWIW, en Android Studio, cuando intento extender BroadcastReceiver, se queja y quiere anular onReceive. Afortunadamente, en mi caso, necesitaba extender ScreenReceiver, que funciona exactamente de la manera que ceph3us describe aquí.
MarkJoel60
Esto realmente no es tan elegante porque debes recordar configurar la bandera isRegistered después de registrarte.
Stealth Rabbi
Sí, aunque puede eliminar esta línea de su sección "en código". myReceiver.isRegistered = true;
Stealth Rabbi
¿No debería ser esta una clase abstracta? extender BroadcastReceiver requiere que implemente el método onReceive.
York Yang
@YorkYang agregó información en la clase en la parte inferior
ceph3us
27

Estoy usando esta solucion

public class ReceiverManager {

    private static List<BroadcastReceiver> receivers = new ArrayList<BroadcastReceiver>();  
    private static ReceiverManager ref;
    private Context context;

    private ReceiverManager(Context context){
        this.context = context;
    }

    public static synchronized ReceiverManager init(Context context) {      
        if (ref == null) ref = new ReceiverManager(context);
        return ref;
    }

    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter intentFilter){
        receivers.add(receiver);
        Intent intent = context.registerReceiver(receiver, intentFilter);
        Log.i(getClass().getSimpleName(), "registered receiver: "+receiver+"  with filter: "+intentFilter);
        Log.i(getClass().getSimpleName(), "receiver Intent: "+intent);
        return intent;
    }

    public boolean isReceiverRegistered(BroadcastReceiver receiver){
        boolean registered = receivers.contains(receiver);
        Log.i(getClass().getSimpleName(), "is receiver "+receiver+" registered? "+registered);
        return registered;
    }

    public void unregisterReceiver(BroadcastReceiver receiver){
        if (isReceiverRegistered(receiver)){
            receivers.remove(receiver);
            context.unregisterReceiver(receiver);
            Log.i(getClass().getSimpleName(), "unregistered receiver: "+receiver);
        }
    }
}
slinden77
fuente
2
jaja, me parece conveniente :) Resumen más rápido sobre el formato y dónde las cosas comienzan y terminan :) cada una a la suya, supongo
slinden77
1
mmm, investigando eso según tu comentario, ¡se ve bien! Por supuesto, arruinó mi espacio de trabajo de Eclipse, pero no se necesita mucho para eso :)
slinden77
2
Oh, cambie a IntelliJ, una vez que se acostumbre, Eclipse se siente realmente viejo;) En el lado positivo, el nuevo Android Studio es solo un IntelliJ con algunos complementos, así que si está acostumbrado a Intellij, Android Studio lo hará. hacerte sentir como en casa.
Martin Marconcini
2
@ MartínMarconcini bueno, finalmente me vi obligado a cambiar a IntelliJ. Me gusta mucho, pero desprecio el hecho de que es imposible trabajar en 2 proyectos simultáneamente.
slinden77
1
Bienvenido al lado oscuro;) Tengo tres Android Studio abiertos en este momento con 3 proyectos diferentes ... no estoy seguro de cuál es su problema de proyectos múltiples, pero puedo asegurarle que funciona con proyectos múltiples. :)
Martin Marconcini
22

Tienes varias opciones

  1. Puedes poner una bandera en tu clase o actividad. Ponga una variable booleana en su clase y mire esta bandera para saber si tiene el receptor registrado.

  2. Cree una clase que extienda el receptor y allí pueda usar:

    1. El patrón Singleton solo tiene una instancia de esta clase en su proyecto.

    2. Implemente los métodos para saber si el receptor está registrado.

chemalarrea
fuente
1
He hecho lo mismo pero mi receptor es AppWidgetProvider y quiero recibir mensajes SCREEN_ON_OFF, pero onDisabled () cuando anulo el registro de Receptor (esto); - Lanza una excepción.
hB0
La primera y la segunda opción combinadas, una bandera en la clase de receptor, funciona enormemente
Gaeburider
¿Me puede dar un ejemplo de código como im no conseguir lo ur haciendo exactamente ... sería de gran ayuda b @chemalarrea
TapanHP
11

Tienes que usar try / catch:

try {
    if (receiver!=null) {
        Activity.this.unregisterReceiver(receiver);
    }
} catch (IllegalArgumentException e) {
    e.printStackTrace();
}
Mohsen mokhtari
fuente
7

Puedes hacerlo fácil ...

1) crear una variable booleana ...

private boolean bolBroacastRegistred;

2) Cuando registre su receptor de transmisión, configúrelo como VERDADERO

...
bolBroacastRegistred = true;
this.registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
....

3) En onPause () hazlo ...

if (bolBroacastRegistred) {
    this.unregisterReceiver(mReceiver);
    bolBroacastRegistred = false
}

Simplemente, y ahora, no recibirá más mensaje de error de excepción en onPause ().

Consejo 1: Utilice siempre unregisterReceiver () en onPause () no en onDestroy () Consejo2: No olvide establecer la variable bolBroadcastRegistred en FALSE cuando ejecute unregisterReceive ()

¡Éxito!

Biruel Rick
fuente
6

Si pones esto en el método onDestroy o onStop. Creo que cuando la actividad se ha creado nuevamente, MessageReciver no se estaba creando.

@Override 
public void onDestroy (){
    super.onDestroy();
LocalBroadcastManager.getInstance(context).unregisterReceiver(mMessageReceiver);

}
eloirobe
fuente
3

Utilicé Intención para informar a Broadcast Receiver sobre la instancia del Manejador del hilo principal de Actividad y utilicé Mensaje para pasar un mensaje a la actividad Principal

He utilizado dicho mecanismo para verificar si Broadcast Receiver ya está registrado o no. A veces es necesario cuando registra su Broadcast Receiver dinámicamente y no desea hacerlo dos veces o si presenta al usuario si Broadcast Receiver está en ejecución.

Actividad principal:

public class Example extends Activity {

private BroadCastReceiver_example br_exemple;

final Messenger mMessenger = new Messenger(new IncomingHandler());

private boolean running = false;

static class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        running = false;    
        switch (msg.what) {
        case BroadCastReceiver_example.ALIVE:
    running = true;
            ....
            break;
        default:

            super.handleMessage(msg);
        }

    }
    }

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    IntentFilter filter = new IntentFilter();
        filter.addAction("pl.example.CHECK_RECEIVER");

        br_exemple = new BroadCastReceiver_example();
        getApplicationContext().registerReceiver(br_exemple , filter); //register the Receiver
    }

// call it whenever you want to check if Broadcast Receiver is running.

private void check_broadcastRunning() {    
        /**
        * checkBroadcastHandler - the handler will start runnable which will check if Broadcast Receiver is running
        */
        Handler checkBroadcastHandler = null;

        /**
        * checkBroadcastRunnable - the runnable which will check if Broadcast Receiver is running
        */
        Runnable checkBroadcastRunnable = null;

        Intent checkBroadCastState = new Intent();
        checkBroadCastState .setAction("pl.example.CHECK_RECEIVER");
        checkBroadCastState .putExtra("mainView", mMessenger);
        this.sendBroadcast(checkBroadCastState );
        Log.d(TAG,"check if broadcast is running");

        checkBroadcastHandler = new Handler();
        checkBroadcastRunnable = new Runnable(){    

            public void run(){
                if (running == true) {
                    Log.d(TAG,"broadcast is running");
                }
                else {
                    Log.d(TAG,"broadcast is not running");
                }
            }
        };
        checkBroadcastHandler.postDelayed(checkBroadcastRunnable,100);
        return;
    }

.............
}

Receptor de radiodifusión:

public class BroadCastReceiver_example extends BroadcastReceiver {


public static final int ALIVE = 1;
@Override
public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    Bundle extras = intent.getExtras();
    String action = intent.getAction();
    if (action.equals("pl.example.CHECK_RECEIVER")) {
        Log.d(TAG, "Received broadcast live checker");
        Messenger mainAppMessanger = (Messenger) extras.get("mainView");
        try {
            mainAppMessanger.send(Message.obtain(null, ALIVE));
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    .........

}

}
jarek
fuente
3

Personalmente utilizo el método de llamar a unregisterReceiver y tragar la excepción si se produce. Estoy de acuerdo en que esto es feo, pero el mejor método proporcionado actualmente.

He planteado una solicitud de función para obtener un método booleano para verificar si un receptor está registrado agregado a la API de Android. Apóyelo aquí si desea verlo agregado: https://code.google.com/p/android/issues/detail?id=73718

ojf
fuente
2

Entiendo su problema, me enfrenté al mismo problema en mi aplicación. Estaba llamando a registerReceiver () varias veces dentro de la aplicación.

Una solución simple a este problema es llamar al registerReceiver () en su clase de aplicación personalizada. Esto asegurará que su receptor Broadcast se llame solo uno en todo el ciclo de vida de la aplicación.

public class YourApplication extends Application
{
    @Override
    public void onCreate()
    {
        super.onCreate();

        //register your Broadcast receiver here
        IntentFilter intentFilter = new IntentFilter("MANUAL_BROADCAST_RECIEVER");
        registerReceiver(new BroadcastReciever(), intentFilter);

    }
}
Sameer Ranjan
fuente
1

Así es como lo hice, es una versión modificada de la respuesta dada por ceph3us y editada por slinden77 (entre otras cosas, he eliminado los valores de retorno de los métodos que no necesitaba):

public class MyBroadcastReceiver extends BroadcastReceiver{
    private boolean isRegistered; 

    public void register(final Context context) {
        if (!isRegistered){
            Log.d(this.toString(), " going to register this broadcast receiver");
            context.registerReceiver(this, new IntentFilter("MY_ACTION"));
            isRegistered = true;
        }
    }
    public void unregister(final Context context) {
        if (isRegistered) {            
            Log.d(this.toString(), " going to unregister this broadcast receiver");
            context.unregisterReceiver(this);
            isRegistered = false;
        }
    }
    @Override
    public void onReceive(final Context context, final Intent intent) {        
        switch (getResultCode()){
        //DO STUFF
        }        
    }        
}

Luego en una clase de actividad:

public class MyFragmentActivity extends SingleFragmentActivity{
    MyBroadcastReceiver myBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        registerBroacastReceiver();       
    }

    @Override
    protected Fragment createFragment(){
        return new MyFragment();
    }

    //This method is called by the fragment which is started by this activity, 
    //when the Fragment is done, we also register the receiver here (if required)
    @Override
    public void receiveDataFromFragment(MyData data) {
        registerBroacastReceiver();
        //Do some stuff                
    }

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

    void registerBroacastReceiver(){
        if (myBroadcastReceiver == null)
            myBroadcastReceiver = new MyBroadcastReceiver();
        myBroadcastReceiver.register(this.getApplicationContext());
    }

    void unregisterReceiver(){
        if (MyBroadcastReceiver != null)
            myBroadcastReceiver.unregister(this.getApplicationContext());
    }
}
Víctor Gil
fuente
1

pongo este código en mi actividad principal

List createdReceivers = new ArrayList <> ();

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    registeredReceivers.add(System.identityHashCode(receiver));
    return super.registerReceiver(receiver, filter);
}

@Override
public void unregisterReceiver(BroadcastReceiver receiver) {
    if(registeredReceivers.contains(System.identityHashCode(receiver)))
    super.unregisterReceiver(receiver);
}
darkwater84
fuente
1

Para mí lo siguiente funcionó:

if (receiver.isOrderedBroadcast()) {
       requireContext().unregisterReceiver(receiver);
}
Benjamin Corben
fuente
0

Esto es lo que hice para verificar si la emisora ​​ya está registrada, incluso si cierra su aplicación (terminar ())

La primera vez que ejecute su aplicación, envíe una transmisión primero, devolverá verdadero / falso, dependiendo de si su emisora ​​sigue ejecutándose o no.

Mi locutor

public class NotificationReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getExtras() != null && intent.getStringExtra("test") != null){
            Log.d("onReceive","test");
            return;
        }
    }
}

Mi actividad principal

// init Broadcaster
private NotificationReceiver nr = new NotificationReceiver();


Intent msgrcv = new Intent("Msg");
msgrcv.putExtra("test", "testing");
boolean isRegistered = LocalBroadcastManager.getInstance(this).sendBroadcast(msgrcv);

if(!isRegistered){
    Toast.makeText(this,"Starting Notification Receiver...",Toast.LENGTH_LONG).show();
    LocalBroadcastManager.getInstance(this).registerReceiver(nr,new IntentFilter("Msg"));
}
janbee
fuente
0

Puede usar Dagger para crear una referencia de ese receptor.

Primero proporcione:

@Provides
@YourScope
fun providesReceiver(): NotificationReceiver{
    return NotificationReceiver()
}

Luego inyecte donde lo necesite (usando constructoro campoinjection )

y simplemente pásalo a registerReceiver .

También póngalo en try/catchbloque también.

Mahdi-Malv
fuente
-3
if( receiver.isOrderedBroadcast() ){
     // receiver object is registered
}
else{
     // receiver object is not registered
}
Kamta Sahu
fuente
1
La transmisión ordenada es algo completamente diferente. Eche un vistazo a este enlace
Vivek Barai
-7

Simplemente marque NullPointerException. Si el receptor no existe, entonces ...

try{
    Intent i = new Intent();
    i.setAction("ir.sss.smsREC");
    context.sendBroadcast(i);
    Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
    e.getMessage();
}
Kasra
fuente
1
¿Cómo / dónde arroja esto un NPE?
DustinB
No arroja ningún error cuando no tiene éxito, en realidad. Tristemente.
Domenukk
2
En realidad, arroja una IllegalArgumentException
portfoliobuilder