Come verificare se il ricevitore è registrato in Android?


Risposte:


68

Non sono sicuro che l'API fornisca direttamente un'API, se si considera questo thread :

Mi chiedevo la stessa cosa.
Nel mio caso ho BroadcastReceiverun'implementazione che chiama Context#unregisterReceiver(BroadcastReceiver)passare se stessa come argomento dopo aver gestito l'intento che riceve.
C'è una piccola possibilità che il onReceive(Context, Intent)metodo del ricevitore sia chiamato più di una volta, poiché è registrato con più IntentFilters, creando il potenziale per IllegalArgumentExceptionessere scartato Context#unregisterReceiver(BroadcastReceiver).

Nel mio caso, posso archiviare un membro sincronizzato privato da controllare prima di chiamare Context#unregisterReceiver(BroadcastReceiver), ma sarebbe molto più pulito se l'API fornisse un metodo di controllo.


313

Non esiste una funzione API per verificare se un ricevitore è registrato. La soluzione alternativa è inserire il codice in atry catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}

83
è un peccato ... :(
Sander Versluys,

4
La cosa divertente è che non rileva l'errore per questa chiamata a BroadcastReceiver per registerReceiver (mReceiver, filter1);
JPM

1
@JPM Sì, lo è. Stavo per archiviare un'istanza del mio ricevitore e controllare per annullarne la registrazione in caso contrario null. Ma come hai sottolineato, vado avanti try catch. Ridicolo.

9
Esegui il downgrade ad Android per non aver creato un'API. +1 per te per aver fornito una soluzione funzionante :)
Denys Vitali

1
Cosa c'è di meglio? usando questo o usando una variabile booleana come flag?
DAVIDBALAS1

34

soluzione più semplice

nel ricevitore:

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 :)
    ...
}

nel codice:

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

annuncio 1

-- in risposta a:

Questo non è poi così elegante perché devi ricordarti di impostare il flag isRegistered dopo la registrazione. - Rabbino invisibile

- "ricevitore più ellegante" ha aggiunto il metodo nel ricevitore per registrare e impostare il flag

questo non funzionerà Se riavvii il dispositivo o se l'app è stata uccisa dal sistema operativo. - Amin 6 ore fa

@amin - vedi la durata del codice in (non il sistema registrato dalla voce manifest) ricevitore registrato :)


2
Questa è davvero una soluzione elegante. FWIW, in Android Studio, quando provo a estendere BroadcastReceiver, si lamenta e desidera eseguire l'override di onReceive. Fortunatamente, nel mio caso, avevo bisogno di estendere ScreenReceiver, che funziona esattamente come ceph3us descrive qui.
MarkJoel60,

Questo non è poi così elegante perché devi ricordarti di impostare il flag isRegistered dopo la registrazione.
Stealth Rabbi,

Sì, sebbene sia possibile rimuovere questa riga dalla sezione "nel codice". myReceiver.isRegistered = true;
Rabbino

non dovrebbe essere una classe astratta? per estendere BroadcastReceiver è necessario implementare il metodo onReceive.
York Yang,

@YorkYang ha aggiunto informazioni in classe in fondo
ceph3us

27

Sto usando questa soluzione

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);
        }
    }
}

2
ahah, li trovo convenienti :) Una panoramica più rapida sul formato e su dove le cose iniziano e finiscono :) ognuna a suo modo, credo
slinden77

1
mmm, esaminandolo come da tuo commento, sta bene! Ovviamente ha rovinato il mio spazio di lavoro Eclipse, ma non c'è molto da fare per questo :)
slinden77,

2
Oh, passa a IntelliJ, una volta che ti ci abitui, Eclipse sembra davvero vecchio;) Tra i lati positivi, il nuovo Android Studio è solo un IntelliJ con alcuni componenti aggiuntivi, quindi se sei abituato a Intellij, Android Studio lo farà ti fanno sentire come a casa.
Martin Marconcini,

2
@ MartínMarconcini finalmente sono stato costretto a passare a IntelliJ. Mi piace moltissimo, ma disprezzo il fatto che sia impossibile lavorare contemporaneamente su 2 progetti.
slinden77,

1
Benvenuto nel lato oscuro;) Ho tre Android Studio aperti in questo momento con 3 progetti diversi ... non sono sicuro di quale sia il tuo problema con più progetti, ma posso assicurarti che funziona con più progetti. :)
Martin Marconcini

22

Hai diverse opzioni

  1. Puoi mettere una bandiera nella tua classe o attività. Inserisci una variabile booleana nella tua classe e osserva questo flag per sapere se hai il ricevitore registrato.

  2. Crea una classe che estende il ricevitore e lì puoi usare:

    1. Il modello Singleton ha solo un'istanza di questa classe nel tuo progetto.

    2. Implementare i metodi per sapere se il ricevitore è registrato.


1
Ho fatto lo stesso, ma il mio ricevitore è AppWidgetProvider e desidero ricevere messaggi SCREEN_ON_OFF - ma onDisabled () quando annullo la registrazione di Receiver (questo); - genera un'eccezione.
hB0,

la prima e la seconda opzione combinate, una bandiera nella classe del ricevitore, funzionano molto bene
Gaeburider,

puoi darmi un esempio di codice perché non riesco a
capire

11

Devi usare try / catch:

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

7

Puoi farlo facilmente ....

1) crea una variabile booleana ...

private boolean bolBroacastRegistred;

2) Quando si registra il ricevitore di trasmissione, impostarlo su TRUE

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

3) In onPause () fallo ...

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

Proprio così, e ora, non riceverai più messaggi di errore di eccezione su onPause ().

Suggerimento1: utilizzare sempre unregisterReceiver () in onPause () non in onDestroy () Suggerimento2: non dimenticare di impostare la variabile bolBroadcastRegistred su FALSE quando si esegue unregisterReceive ()

Successo!


6

Se lo metti sul metodo onDestroy o onStop. Penso che quando l'attività è stata creata di nuovo, MessageReciver non è stato creato.

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

}

3

Ho usato Intent per informare Broadcast Receiver sull'istanza di Handler del thread principale delle attività e ho usato Message per passare un messaggio all'attività principale

Ho usato tale meccanismo per verificare se Broadcast Receiver è già registrato o meno. A volte è necessario quando si registra dinamicamente il ricevitore Broadcast e non si desidera farlo due volte o si presenta all'utente se Broadcast Receiver è in esecuzione.

Attività principale:

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;
    }

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

Ricevitore broadcast:

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();
        }
    }
    .........

}

}

3

Personalmente uso il metodo per chiamare unregisterReceiver e ingoiare l'eccezione se viene generata. Sono d'accordo che sia brutto ma il miglior metodo attualmente fornito.

Ho sollevato una richiesta di funzionalità per ottenere un metodo booleano per verificare se un ricevitore è registrato aggiunto all'API Android. Supportalo qui se vuoi vederlo aggiunto: https://code.google.com/p/android/issues/detail?id=73718


2

Ottengo il tuo problema, ho riscontrato lo stesso problema nella mia applicazione. Stavo chiamando registerReceiver () più volte all'interno dell'applicazione.

Una soluzione semplice a questo problema è chiamare registerReceiver () nella propria classe di applicazione personalizzata. Questo assicurerà che il tuo ricevitore Broadcast verrà chiamato solo uno nell'intero ciclo di vita dell'applicazione.

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);

    }
}

1

È così che l'ho fatto, è una versione modificata della risposta data da ceph3us e modificata da slinden77 (tra le altre cose ho rimosso valori di ritorno di metodi che non mi servivano):

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
        }        
    }        
}

Quindi su una classe Activity:

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());
    }
}

1

ho inserito questo codice nella mia attività genitore

Elenco RegisterReceivers = 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);
}

1

Per me ha funzionato:

if (receiver.isOrderedBroadcast()) {
       requireContext().unregisterReceiver(receiver);
}

0

Ecco cosa ho fatto per verificare se l'emittente è già registrata, anche se chiudi l'applicazione (finish ())

Prima di avviare l'applicazione, inviare prima una trasmissione che restituirà vero / falso dipende dal fatto che l'emittente sia ancora in esecuzione o meno.

La mia emittente

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;
        }
    }
}

La mia attività principale

// 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"));
}

0

Puoi usare il Pugnale per creare un riferimento di quel ricevitore.

Prima forniscilo:

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

Quindi iniettalo dove ti serve (usando constructoro campo injection)

e semplicemente passalo a registerReceiver.

Mettilo anche in try/catchblocco.


-3
if( receiver.isOrderedBroadcast() ){
     // receiver object is registered
}
else{
     // receiver object is not registered
}

1
Ordinato Broadcast è completamente un'altra cosa dare un'occhiata a questo link
Vivek Barai

-7

Basta controllare NullPointerException. Se il ricevitore non esiste, quindi ...

try{
    Intent i = new Intent();
    i.setAction("ir.sss.smsREC");
    context.sendBroadcast(i);
    Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
    e.getMessage();
}

1
Come / dove questo genera un NPE?
DustinB,

In realtà non genera errori quando non ha successo. Purtroppo.
domenukk,

2
In realtà, genera un'eccezione IllegalArgumentException
portfoliobuilder il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.