289

I need to check if my registered receiver is still registered if not how do i check it any methods?

Henke
  • 4,445
  • 3
  • 31
  • 44
Mikey
  • 4,218
  • 3
  • 25
  • 25

17 Answers17

355

There is no API function to check if a receiver is registered. The workaround is to put your code in a try catch block as done below.

try {

 //Register or UnRegister your broadcast receiver here

} catch(IllegalArgumentException e) {

    e.printStackTrace();
}
David Kariuki
  • 1,522
  • 1
  • 15
  • 30
Daniel
  • 26,899
  • 12
  • 60
  • 88
  • 4
    Funny thing is that doesn't catch the error for this call to BroadcastReceiver for registerReceiver(mReceiver, filter1); – JPM Mar 02 '12 at 17:10
  • 1
    @JPM Yes it is. I was going to store an instance of my receiver and check to unregister it if it is not `null`. But as you pointed out, I'm going with `try catch`. Ridiculous. –  Nov 27 '12 at 21:42
  • 20
    Downvote to Android for not creating an API for that. +1 to you for providing a working solution :) – Denys Vitali Mar 23 '16 at 08:47
  • 1
    What's better? using this or using a boolean variable as a flag? – DAVIDBALAS1 Aug 19 '16 at 09:39
  • @DAVIDBALAS1 I think that it may depend on the use case. I've elected to use a boolean, because that variable is useful for me again. – AlbertMarkovski Sep 29 '16 at 22:26
  • 1
    I will go with this instead of boolean variable as a flag, because i don't want to make 1 more variable on my class and maintain the state of the flag. Especially if my class is already big – HendraWD Oct 20 '16 at 04:30
  • I will go with this instead of boolean variable as a flag, because if the registering is still hanging for any reason and the flag has not been set to true yet, then the unregistering would still raise the exception – ocramot May 10 '18 at 14:14
  • I posted a similar concern of querying the MediaCodec's state. Please check if it's of interest: https://stackoverflow.com/q/51780322/1562087 – KenIchi Aug 24 '18 at 09:01
  • But how can you be sure the exception will be thrown if it's not on the method signature nor anywhere? (At least I don't see anywhere mentioning the exception will be thrown.) – Edw590 Jul 26 '21 at 00:51
76

I am not sure the API provides directly an API, if you consider this thread:

I was wondering the same thing.
In my case I have a BroadcastReceiver implementation that calls Context#unregisterReceiver(BroadcastReceiver) passing itself as the argument after handling the Intent that it receives.
There is a small chance that the receiver's onReceive(Context, Intent) method is called more than once, since it is registered with multiple IntentFilters, creating the potential for an IllegalArgumentException being thrown from Context#unregisterReceiver(BroadcastReceiver).

In my case, I can store a private synchronized member to check before calling Context#unregisterReceiver(BroadcastReceiver), but it would be much cleaner if the API provided a check method.

David Kariuki
  • 1,522
  • 1
  • 15
  • 30
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
35

simplest solution

in receiver:

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

-- in reply to:

This really isn't that elegant because you have to remember to set the isRegistered flag after you register. – Stealth Rabbi

-- "more ellegant way" added method in receiver to register and set flag

this won't work If you restart the device or if your app got killed by OS. – amin 6 hours ago

@amin - see lifetime of in code (not system registered by manifest entry) registered receiver :)

Abhay Pai
  • 314
  • 4
  • 17
ceph3us
  • 7,326
  • 3
  • 36
  • 43
  • 2
    This really is an elegant solution. FWIW, in Android Studio, when I try to extend BroadcastReceiver, it complains and wants an override of onReceive. Fortunately, in my case, I was needing to extend ScreenReceiver, which operates exactly the way ceph3us describes here. – MarkJoel60 Oct 24 '15 at 13:48
  • This really isn't that elegant because you have to remember to set the isRegistered flag after you register. – Stealth Rabbi Feb 15 '16 at 15:05
  • Yes, although you can remove this line from your "in code" section. myReceiver.isRegistered = true; – Stealth Rabbi Feb 16 '16 at 12:07
  • shouldn't this be an abstract class? extending BroadcastReceiver requires you to implement the onReceive method. – York Yang Aug 09 '17 at 03:24
  • @YorkYang added info in class at the bottom – ceph3us Aug 09 '17 at 12:56
  • 1
    this won't work If you restart the device or if your app got killed by OS. – Amin Pinjari Apr 30 '19 at 07:39
30

I use this solution:

public class ReceiverManager {
    private WeakReference<Context> cReference;
    private static List<BroadcastReceiver> receivers = new ArrayList<BroadcastReceiver>();
    private static ReceiverManager ref;

    private ReceiverManager(Context context) {
        cReference = new WeakReference<>(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 = cReference.get().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);
            cReference.get().unregisterReceiver(receiver);
            Log.i(getClass().getSimpleName(), "unregistered receiver: " + receiver);
        }
    }
}
bighugedev
  • 379
  • 1
  • 3
  • 11
slinden77
  • 3,378
  • 2
  • 37
  • 35
  • 2
    haha, I find them convenient :) Quicker overview on the format and where stuff starts and ends :) eacht to his own I guess – slinden77 May 24 '13 at 22:41
  • 1
    mmm, looking into that as per your comment, looking good! Ofcourse it screwed up my Eclipse workspace, but not much is needed for that :) – slinden77 May 27 '13 at 21:11
  • 2
    Oh, switch to IntelliJ, once you get used to it, Eclipse feels really old ;) On the plus side, the new Android Studio is just an IntelliJ with a few add-ons so if you're used to Intellij, Android Studio will make you feel right at home. – Martin Marconcini May 28 '13 at 05:23
  • 2
    @MartínMarconcini well finally I was forced to switch to IntelliJ. I like it very much, but I despise the fact it's impossible to work in 2 projects simultaniously. – slinden77 Aug 16 '16 at 17:59
  • 1
    Welcome to the dark side ;) I have three Android Studio open right now with 3 different projects… not sure what your multiple-project problem is, but I can assure you that it works with multiple projects. :) – Martin Marconcini Aug 16 '16 at 20:48
  • 1
    down for leaked context (have you heard about weak references) ? – ceph3us Aug 09 '17 at 09:43
  • It's from the TelephonyManager class? @slinden77 – exploitr Jun 27 '18 at 05:21
  • Also, your code pushes memory leaks. Try no to place context classes in static fields. Use WeakReference. Anyway +1 – exploitr Jun 27 '18 at 05:25
  • I have made an edit for holding the content within a WeakReference. – Steve Kamau Jul 14 '20 at 10:06
22

You have several options

  1. You can put a flag into your class or activity. Put a boolean variable into your class and look at this flag to know if you have the Receiver registered.

  2. Create a class that extends the Receiver and there you can use:

    1. Singleton pattern for only have one instance of this class in your project.

    2. Implement the methods for know if the Receiver is register.

Peter O.
  • 32,158
  • 14
  • 82
  • 96
chemalarrea
  • 1,385
  • 13
  • 11
  • 1
    I have done the same but my receiver is the AppWidgetProvider and I want to receive SCREEN_ON_OFF messages - but onDisabled() when I unregisterReceiver(this); - it throws exception. – hB0 Jul 12 '13 at 17:40
  • combined first and second option, a flag in the receiver class, works greatly – Gaeburider Jun 05 '14 at 17:56
  • can you give me a code example as i m not getting what u r exactly doing...would b great help @chemalarrea – TapanHP Jan 18 '17 at 14:10
14

You have to use try/catch:

try {
    if (receiver!=null) {
        Activity.this.unregisterReceiver(receiver);
    }
} catch (IllegalArgumentException e) {
    e.printStackTrace();
}
Melquiades
  • 8,496
  • 1
  • 31
  • 46
Mohsen mokhtari
  • 2,841
  • 1
  • 30
  • 39
9

You can do it easy....

1) create a boolean variable ...

private boolean bolBroacastRegistred;

2) When you register your Broadcast Receiver, set it to TRUE

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

3) In the onPause() do it...

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

Just it, and now, you will not receive more exception error message on onPause().

Tip1: Always use the unregisterReceiver() in onPause() not in onDestroy() Tip2: Dont forget to set the bolBroadcastRegistred variable to FALSE when run the unregisterReceive()

Success!

Biruel Rick
  • 776
  • 1
  • 8
  • 17
6

If you put this on onDestroy or onStop method. I think that when the activity has been created again the MessageReciver wasn't being created.

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

}
eloirobe
  • 152
  • 1
  • 5
4

Personally I use the method of calling unregisterReceiver and swallowing the exception if it's thrown. I agree this is ugly but the best method currently provided.

I've raised a feature request to get a boolean method to check if a receiver is registered added to the Android API. Please support it here if you want to see it added: https://code.google.com/p/android/issues/detail?id=73718

ojf
  • 163
  • 1
  • 6
3

I used Intent to let Broadcast Receiver know about Handler instance of main Activity thread and used Message to pass a message to Main activity

I have used such mechanism to check if Broadcast Receiver is already registered or not. Sometimes it is needed when you register your Broadcast Receiver dynamically and do not want to make it twice or you present to the user if Broadcast Receiver is running.

Main activity:

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

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

Broadcast Receiver:

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
  • 41
  • 1
2

i put this code in my parent activity

List registeredReceivers = 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
  • 103
  • 6
2

I get your problem, I faced the same problem in my Application. I was calling registerReceiver() multiple time within the application.

A simple solution to this problem is to call the registerReceiver() in your Custom Application Class. This will ensure that your Broadcast receiver will be called only one in your entire Application lifecycle.

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

This is how I have done it, it is a modified version of the answer given by ceph3us and edited by slinden77 (among other things I have removed return values of methods which I did not need):

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

Then on an Activity class:

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
  • 835
  • 8
  • 10
1

For me the following worked:

if (receiver.isOrderedBroadcast()) {
   requireContext().unregisterReceiver(receiver);
}
Benjamin Corben
  • 277
  • 3
  • 10
  • This does not work (tested to verify). The receiver.isOrderedBroadcast() condition is not a stand-in for determining if a BroadcastReceiver is registered. It returns false even for legitimately registered BroadcastReceivers (again, tested it to verify). There is as yet no way in the API to determine if a BroadcastReceiver is registered. Just a minor oversight by the Android team. – ONE Nov 19 '21 at 01:49
  • This is not working. Have you tested this before posting here? Share source URL – Kishan Solanki May 16 '22 at 05:39
0

Here's what I did to check if the Broadcaster is already registered, even if you close you application (finish())

Firstime running your application, send a broadcast first it will return true/false depends on if your broadcaster in still running or not.

My Broadcaster

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

My MainActivity

// 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
  • 141
  • 1
  • 6
-3
if( receiver.isOrderedBroadcast() ){
     // receiver object is registered
}
else{
     // receiver object is not registered
}
Kamta Sahu
  • 150
  • 1
  • 9
  • 1
    Ordered Broadcast is completely another thing have a look at [this link](https://android-developers.googleblog.com/2011/01/processing-ordered-broadcasts.html) – Vivek Barai Nov 14 '17 at 07:14
-9

Just check NullPointerException. If receiver does not exist, then...

try{
    Intent i = new Intent();
    i.setAction("ir.sss.smsREC");
    context.sendBroadcast(i);
    Log.i("...","broadcast sent");
}
catch (NullPointerException e)
{
    e.getMessage();
}
superpuccio
  • 11,674
  • 8
  • 65
  • 93
Kasra
  • 1