Wie überprüfe ich, ob Receiver in Android registriert ist?

Antworten:

68

Ich bin nicht sicher, ob die API direkt eine API bereitstellt, wenn Sie diesen Thread berücksichtigen :

Ich habe mich das Gleiche gefragt.
In meinem Fall habe ich eine BroadcastReceiverImplementierung, die aufruft Context#unregisterReceiver(BroadcastReceiver), sich selbst als Argument zu übergeben, nachdem die empfangene Absicht behandelt wurde.
Es besteht eine geringe Wahrscheinlichkeit, dass die onReceive(Context, Intent)Methode des Empfängers mehrmals aufgerufen wird, da sie mit mehreren registriert ist IntentFilters, wodurch das Potenzial für ein IllegalArgumentExceptionWerfen entsteht Context#unregisterReceiver(BroadcastReceiver).

In meinem Fall kann ich ein privates synchronisiertes Mitglied speichern, um es vor dem Aufruf zu überprüfen. Context#unregisterReceiver(BroadcastReceiver)Es wäre jedoch viel sauberer, wenn die API eine Überprüfungsmethode bereitstellen würde.

VonC
quelle
313

Es gibt keine API-Funktion, um zu überprüfen, ob ein Empfänger registriert ist. Die Problemumgehung besteht darin, Ihren Code in a zu setzentry catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}
Daniel Velkov
quelle
83
das ist ein Mist ... :(
Sander Versluys
4
Lustige Sache ist, dass der Fehler für diesen Aufruf von BroadcastReceiver für registerReceiver (mReceiver, filter1) nicht abgefangen wird;
JPM
1
@ JPM Ja, das ist es. Ich wollte eine Instanz meines Empfängers speichern und prüfen, ob die Registrierung aufgehoben werden soll, wenn dies nicht der Fall ist null. Aber wie Sie betont haben, gehe ich mit try catch. Lächerlich.
9
Stimmen Sie für Android ab, weil Sie dafür keine API erstellt haben. +1 an Sie für die Bereitstellung einer funktionierenden Lösung :)
Denys Vitali
1
Was ist besser? Verwenden Sie diese oder eine boolesche Variable als Flag?
DAVIDBALAS1
34

einfachste Lösung

im Empfänger:

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

in Code:

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

ad 1

-- als Antwort auf:

Das ist wirklich nicht so elegant, weil Sie daran denken müssen, das isRegistered-Flag zu setzen, nachdem Sie sich registriert haben. - Stealth Rabbi

- "elleganter Weg" hinzugefügt Methode im Empfänger, um zu registrieren und Flag zu setzen

Dies funktioniert nicht, wenn Sie das Gerät neu starten oder wenn Ihre App vom Betriebssystem beendet wurde. - Amin vor 6 Stunden

@amin - siehe Lebensdauer des im Code (nicht durch Manifesteintrag registriertes System) registrierten Empfängers :)

ceph3us
quelle
2
Dies ist wirklich eine elegante Lösung. FWIW, in Android Studio, wenn ich versuche, BroadcastReceiver zu erweitern, beschwert es sich und möchte eine Überschreibung von onReceive. Glücklicherweise musste ich in meinem Fall ScreenReceiver erweitern, der genau so funktioniert, wie ceph3us es hier beschreibt.
MarkJoel60
Das ist wirklich nicht so elegant, weil Sie daran denken müssen, das isRegistered-Flag zu setzen, nachdem Sie sich registriert haben.
Stealth Rabbi
Ja, obwohl Sie diese Zeile aus Ihrem Abschnitt "In Code" entfernen können. myReceiver.isRegistered = true;
Stealth Rabbi
Sollte dies nicht eine abstrakte Klasse sein? Für die Erweiterung von BroadcastReceiver müssen Sie die onReceive-Methode implementieren.
York Yang
@ YorkYang fügte Informationen in der Klasse unten hinzu
ceph3us
27

Ich benutze diese Lösung

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
quelle
2
haha, ich finde sie praktisch :) Schnellerer Überblick über das Format und wo Dinge beginnen und enden :) Ich denke, er hat es geschafft
slinden77
1
mmm, schauen Sie sich das gemäß Ihrem Kommentar an und sehen Sie gut aus! Natürlich hat es meinen Eclipse-Arbeitsbereich vermasselt, aber dafür wird nicht viel benötigt :)
slinden77
2
Oh, wechseln Sie zu IntelliJ, sobald Sie sich daran gewöhnt haben, fühlt sich Eclipse wirklich alt an;) Auf der positiven Seite ist das neue Android Studio nur ein IntelliJ mit ein paar Add-Ons. Wenn Sie also an Intellij gewöhnt sind, wird Android Studio es tun Sie fühlen sich wie zu Hause.
Martin Marconcini
2
@ MartínMarconcini Nun, endlich musste ich zu IntelliJ wechseln. Ich mag es sehr, aber ich verachte die Tatsache, dass es unmöglich ist, in 2 Projekten gleichzeitig zu arbeiten.
Slinden77
1
Willkommen auf der dunklen Seite;) Ich habe momentan drei Android Studios mit drei verschiedenen Projekten geöffnet. Ich bin mir nicht sicher, was Ihr Problem mit mehreren Projekten ist, aber ich kann Ihnen versichern, dass es mit mehreren Projekten funktioniert. :)
Martin Marconcini
22

Sie haben mehrere Möglichkeiten

  1. Sie können Ihrer Klasse oder Aktivität eine Flagge hinzufügen. Fügen Sie eine boolesche Variable in Ihre Klasse ein und überprüfen Sie anhand dieses Flags, ob der Empfänger registriert ist.

  2. Erstellen Sie eine Klasse, die den Empfänger erweitert, und verwenden Sie dort:

    1. Singleton-Muster für nur eine Instanz dieser Klasse in Ihrem Projekt.

    2. Implementieren Sie die Methoden, um festzustellen, ob der Empfänger registriert ist.

chemalarrea
quelle
1
Ich habe das Gleiche getan, aber mein Empfänger ist der AppWidgetProvider und ich möchte SCREEN_ON_OFF-Nachrichten empfangen - aber onDisabled (), wenn ich die Registrierung von reeceiver (this) aufhebe; - Es wird eine Ausnahme ausgelöst.
hB0
Die kombinierte erste und zweite Option, eine Flagge in der Empfängerklasse, funktioniert
hervorragend
Können Sie mir ein Codebeispiel geben, da ich nicht verstehe, was Sie genau tun ... wäre eine große Hilfe @chemalarrea
TapanHP
11

Sie müssen try / catch verwenden:

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

Sie können es einfach machen ....

1) Erstellen Sie eine boolesche Variable ...

private boolean bolBroacastRegistred;

2) Wenn Sie Ihren Rundfunkempfänger registrieren, setzen Sie ihn auf TRUE

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

3) In der onPause () mach es ...

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

Nur so, und jetzt erhalten Sie keine weitere Ausnahmefehlermeldung auf onPause ().

Tipp 1: Verwenden Sie immer den unregisterReceiver () in onPause () und nicht in onDestroy (). Tipp 2: Vergessen Sie nicht, die Variable bolBroadcastRegistred auf FALSE zu setzen, wenn Sie unregisterReceive () ausführen.

Erfolg!

Biruel Rick
quelle
6

Wenn Sie dies auf die Methode onDestroy oder onStop setzen. Ich denke, wenn die Aktivität erneut erstellt wurde, wurde der MessageReciver nicht erstellt.

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

}
eloirobe
quelle
3

Ich habe Intent verwendet, um Broadcast Receiver über die Handler-Instanz des Hauptaktivitätsthreads zu informieren, und habe Nachricht verwendet, um eine Nachricht an die Hauptaktivität zu übergeben

Ich habe einen solchen Mechanismus verwendet, um zu überprüfen, ob der Rundfunkempfänger bereits registriert ist oder nicht. Manchmal ist dies erforderlich, wenn Sie Ihren Broadcast-Empfänger dynamisch registrieren und nicht zweimal erstellen möchten oder wenn Sie dem Benutzer präsentieren, ob der Broadcast-Empfänger ausgeführt wird.

Hauptaktivität:

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

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

Rundfunkempfänger:

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
quelle
3

Persönlich verwende ich die Methode, unregisterReceiver aufzurufen und die Ausnahme zu schlucken, wenn sie ausgelöst wird. Ich bin damit einverstanden, dass dies hässlich ist, aber die derzeit beste Methode.

Ich habe eine Funktionsanforderung ausgelöst, um eine boolesche Methode zu erhalten, mit der überprüft werden kann, ob ein Empfänger registriert ist, der der Android-API hinzugefügt wurde. Bitte unterstützen Sie es hier, wenn Sie möchten, dass es hinzugefügt wird: https://code.google.com/p/android/issues/detail?id=73718

ojf
quelle
2

Ich habe Ihr Problem, ich hatte das gleiche Problem in meiner Bewerbung. Ich habe registerReceiver () mehrmals in der Anwendung aufgerufen.

Eine einfache Lösung für dieses Problem besteht darin, registerReceiver () in Ihrer benutzerdefinierten Anwendungsklasse aufzurufen. Dadurch wird sichergestellt, dass Ihr Broadcast-Empfänger in Ihrem gesamten Anwendungslebenszyklus nur als einer bezeichnet wird.

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
quelle
1

So habe ich es gemacht, es ist eine modifizierte Version der Antwort von ceph3us und bearbeitet von slinden77 (unter anderem habe ich Rückgabewerte von Methoden entfernt, die ich nicht brauchte):

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

Dann auf einer Aktivitätsklasse:

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
quelle
1

Ich habe diesen Code in meine übergeordnete Aktivität eingefügt

List 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);
}
darkwater84
quelle
1

Für mich hat folgendes funktioniert:

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

Folgendes habe ich getan, um zu überprüfen, ob der Sender bereits registriert ist, auch wenn Sie Ihre Anwendung schließen (finish ()).

Wenn Sie Ihre Anwendung zum ersten Mal ausführen, senden Sie zuerst eine Sendung, die true / false zurückgibt. Dies hängt davon ab, ob Ihr Sender noch ausgeführt wird oder nicht.

Mein Sender

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

Meine Hauptaktivität

// 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
quelle
0

Sie können Dolch verwenden , um eine Referenz dieses Empfängers zu erstellen.

Stellen Sie es zuerst bereit:

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

Dann injizieren Sie es, wo Sie es brauchen (mit constructoroder Feld injection)

und einfach weitergeben an registerReceiver.

Legen Sie es auch in try/catchBlock.

Mahdi-Malv
quelle
-3
if( receiver.isOrderedBroadcast() ){
     // receiver object is registered
}
else{
     // receiver object is not registered
}
Kamta Sahu
quelle
1
Bestellte Sendung ist eine ganz andere Sache. Schauen Sie sich diesen Link an
Vivek Barai
-7

Überprüfen Sie einfach die NullPointerException. Wenn der Empfänger nicht existiert, dann ...

try{
    Intent i = new Intent();
    i.setAction("ir.sss.smsREC");
    context.sendBroadcast(i);
    Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
    e.getMessage();
}
Kasra
quelle
1
Wie / wo wirft das eine NPE?
DustinB
Es werden keine Fehler ausgegeben, wenn es tatsächlich nicht erfolgreich ist. Traurig.
Domenukk
2
Tatsächlich löst es eine IllegalArgumentException
portfoliobuilder