Jak sprawdzić, czy odbiornik jest zarejestrowany w systemie Android?

Odpowiedzi:

68

Nie jestem pewien, czy interfejs API zapewnia bezpośrednio interfejs API, jeśli weźmiesz pod uwagę ten wątek :

Zastanawiałem się nad tym samym.
W moim przypadku mam BroadcastReceiverimplementację, która wywołuje Context#unregisterReceiver(BroadcastReceiver)przekazanie siebie jako argumentu po przetworzeniu otrzymanej intencji.
Istnieje niewielka szansa, że onReceive(Context, Intent)metoda odbiornika zostanie wywołana więcej niż jeden raz, ponieważ jest zarejestrowana z wieloma IntentFilters, co stwarza możliwość IllegalArgumentExceptionwyrzucenia Context#unregisterReceiver(BroadcastReceiver).

W moim przypadku mogę zapisać prywatnego zsynchronizowanego członka do sprawdzenia przed wywołaniem Context#unregisterReceiver(BroadcastReceiver), ale byłoby znacznie czystsze, gdyby interfejs API zapewniał metodę sprawdzania.

VonC
źródło
313

Brak funkcji API sprawdzającej, czy odbiornik jest zarejestrowany. Obejściem tego problemu jest umieszczenie kodu w plikutry catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}
Daniel Velkov
źródło
83
to jest bummer ... :(
Sander Versluys
4
Zabawne jest to, że nie wychwytuje błędu tego połączenia do BroadcastReceiver dla registerReceiver (mReceiver, filter1);
JPM
1
@JPM Tak to jest. Zamierzałem zapisać instancję mojego odbiornika i zaznaczyć, aby ją wyrejestrować, jeśli nie jest null. Ale jak wskazałeś, idę z try catch. Śmieszny.
9
Zgłoś głos na Androida, aby nie tworzyć interfejsu API do tego. +1 dla ciebie za dostarczenie działającego rozwiązania :)
Denys Vitali
1
Co lepsze? używasz tego czy używasz zmiennej boolean jako flagi?
DAVIDBALAS1
34

najprostsze rozwiązanie

w odbiorniku:

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

W kodzie:

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

ad 1

-- w odpowiedzi na:

To naprawdę nie jest tak eleganckie, ponieważ musisz pamiętać, aby ustawić flagę isRegistered po rejestracji. - Stealth Rabbi

- Dodano „bardziej eliptyczny sposób” w odbiorniku, aby zarejestrować i ustawić flagę

to nie zadziała Jeśli ponownie uruchomisz urządzenie lub Twoja aplikacja została zabita przez system operacyjny. - amin 6 godzin temu

@amin - zobacz czas życia w kodzie (niezarejestrowany w systemie przez wpis manifestu) zarejestrowany odbiorca :)

ceph3us
źródło
2
To naprawdę eleganckie rozwiązanie. FWIW, w Android Studio, kiedy próbuję rozszerzyć BroadcastReceiver, narzeka i chce zastąpić onReceive. Na szczęście w moim przypadku musiałem rozszerzyć ScreenReceiver, który działa dokładnie tak, jak opisuje to tutaj ceph3us.
MarkJoel60
To naprawdę nie jest tak eleganckie, ponieważ musisz pamiętać, aby ustawić flagę isRegistered po rejestracji.
Stealth Rabbi
Tak, chociaż możesz usunąć ten wiersz z sekcji „w kodzie”. myReceiver.isRegistered = true;
Stealth Rabbi
czy nie powinna to być klasa abstrakcyjna? rozszerzenie BroadcastReceiver wymaga zaimplementowania metody onReceive.
York Yang,
@YorkYang dodał informacje w klasie na dole
ceph3us
27

Korzystam z tego rozwiązania

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
źródło
2
haha, uważam je za wygodne :) Szybszy przegląd formatu i miejsca, w którym zaczyna się i kończy rzeczy :) Myślę, że
każdy z nich
1
mmm, patrząc na to zgodnie z twoim komentarzem, dobrze wygląda! Oczywiście spieprzyło to mój obszar roboczy Eclipse, ale niewiele do tego potrzeba :)
slinden77
2
Och, przełącz się na IntelliJ, gdy już się przyzwyczaisz, Eclipse wydaje się bardzo stary;) Plusem jest to, że nowy Android Studio to tylko IntelliJ z kilkoma dodatkami, więc jeśli jesteś przyzwyczajony do Intellij, Android Studio będzie sprawi, że poczujesz się jak w domu.
Martin Marconcini
2
@ MartínMarconcini dobrze wreszcie byłem zmuszony przejść na IntelliJ. Bardzo mi się podoba, ale gardzę faktem, że nie można pracować jednocześnie w dwóch projektach.
slinden77
1
Witaj w ciemnej stronie;) Mam teraz otwarte trzy Android Studio z 3 różnymi projektami… nie jestem pewien, na czym polega twój problem z wieloma projektami, ale zapewniam cię, że działa z wieloma projektami. :)
Martin Marconcini,
22

Masz kilka opcji

  1. Możesz umieścić flagę w swojej klasie lub aktywności. Umieść zmienną boolowską w swojej klasie i spójrz na tę flagę, aby dowiedzieć się, czy masz zarejestrowanego odbiornika.

  2. Utwórz klasę rozszerzającą odbiornik i tam możesz użyć:

    1. Wzorzec singletonu dla tylko jednego wystąpienia tej klasy w twoim projekcie.

    2. Zaimplementuj metody sprawdzania, czy odbiornik jest zarejestrowany.

chemalarrea
źródło
1
Zrobiłem to samo, ale moim odbiornikiem jest AppWidgetProvider i chcę otrzymywać wiadomości SCREEN_ON_OFF - ale onDisabled (), gdy wyrejestrujęReceiver (this); - rzuca wyjątek.
hB0,
Połączona pierwsza i druga opcja, flaga w klasie odbiorników, działa bardzo dobrze
Gaeburider
możesz dać mi przykład kodu, jak im nie dostanę, co dokładnie robi ur ... byłoby bardzo pomocne @chemalarrea b
TapanHP
11

Musisz użyć try / catch:

try {
    if (receiver!=null) {
        Activity.this.unregisterReceiver(receiver);
    }
} catch (IllegalArgumentException e) {
    e.printStackTrace();
}
Mohsen mokhtari
źródło
7

Możesz to zrobić łatwo ....

1) utwórz zmienną boolowską ...

private boolean bolBroacastRegistred;

2) Po zarejestrowaniu odbiornika rozgłoszeniowego ustaw go na PRAWDA

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

3) W onPause () zrób to ...

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

Po prostu, a teraz nie otrzymasz więcej komunikatu o błędzie wyjątku na onPause ().

Tip1: Zawsze używaj unregisterReceiver () w onPause (), a nie w onDestroy () Tip2: Nie zapomnij ustawić zmiennej bolBroadcastRegistred na FALSE podczas uruchamiania unregisterReceive ()

Sukces!

Biruel Rick
źródło
6

Jeśli umieścisz to w metodzie onDestroy lub onStop. Myślę, że po ponownym utworzeniu działania MessageReciver nie był tworzony.

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

}
eloirobe
źródło
3

Użyłem Intent, aby poinformować Odbiorcę transmisji o wystąpieniu modułu głównego wątku działania programu Handler i użyłem komunikatu, aby przekazać wiadomość do głównej aktywności

Użyłem takiego mechanizmu, aby sprawdzić, czy odbiornik jest już zarejestrowany, czy nie. Czasami jest to potrzebne, gdy rejestrujesz swój odbiornik dynamiczny dynamicznie i nie chcesz, aby był dwa razy lub prezentujesz się użytkownikowi, jeśli odbiornik jest uruchomiony.

Główna aktywność:

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

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

Odbiornik transmisji:

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
źródło
3

Osobiście używam metody wywoływania unregisterReceiver i połykania wyjątku, jeśli zostanie zgłoszony. Zgadzam się, że to brzydkie, ale najlepsza obecnie dostępna metoda.

Podniosłem żądanie funkcji, aby uzyskać metodę logiczną, aby sprawdzić, czy odbiornik jest zarejestrowany dodany do interfejsu API Androida. Wesprzyj go tutaj, jeśli chcesz, aby został dodany: https://code.google.com/p/android/issues/detail?id=73718

ojf
źródło
2

Rozumiem twój problem, napotkałem ten sam problem w mojej aplikacji. Dzwoniłem registerReceiver () wiele razy w aplikacji.

Prostym rozwiązaniem tego problemu jest wywołanie registerReceiver () w niestandardowej klasie aplikacji. Zapewni to, że odbiornik Broadcast będzie nazywany tylko jednym w całym cyklu życia aplikacji.

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
źródło
1

Tak to zrobiłem, jest to zmodyfikowana wersja odpowiedzi udzielonej przez ceph3us i edytowanej przez slinden77 (między innymi usunąłem zwracane wartości metod, których nie potrzebowałem):

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

Następnie na zajęciach:

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
źródło
1

umieszczam ten kod w mojej działalności nadrzędnej

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
źródło
1

Dla mnie działało:

if (receiver.isOrderedBroadcast()) {
       requireContext().unregisterReceiver(receiver);
}
Benjamin Corben
źródło
0

Oto, co zrobiłem, aby sprawdzić, czy nadawca jest już zarejestrowany, nawet jeśli zamkniesz aplikację (zakończ ())

Przy pierwszym uruchomieniu aplikacji wyślij najpierw transmisję, która zwróci wartość prawda / fałsz, w zależności od tego, czy nadawca nadal działa, czy nie.

Mój nadawca

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

Moja główna aktywność

// 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
źródło
0

Możesz użyć Sztyletu, aby utworzyć odniesienie do tego odbiornika.

Najpierw podaj:

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

Następnie wstrzyknij go tam, gdzie potrzebujesz (za pomocą constructorlub pola injection)

i po prostu przekażcie to registerReceiver.

Również włóż to w try/catchblok.

Mahdi-Malv
źródło
-3
if( receiver.isOrderedBroadcast() ){
     // receiver object is registered
}
else{
     // receiver object is not registered
}
Kamta Sahu
źródło
1
Uporządkowana transmisja to zupełnie inna rzecz, spójrz na ten link
Vivek Barai
-7

Wystarczy sprawdzić NullPointerException. Jeśli odbiornik nie istnieje, to ...

try{
    Intent i = new Intent();
    i.setAction("ir.sss.smsREC");
    context.sendBroadcast(i);
    Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
    e.getMessage();
}
Kasra
źródło
1
Jak / gdzie to powoduje NPE?
DustinB
W rzeczywistości nie generuje żadnych błędów, gdy się nie powiedzie. Niestety
domenukk
2
W rzeczywistości generuje wyjątek IllegalArgumentException
portfoliobuilder