137

I have an Android Activity that needs to catch two different broadcasts. My current approach is to have a single BroadcastReceiver within the Activity and catch both the broadcasts with it:

public class MyActivity extends Activity {
    private MyActivity.BroadcastListener mBroadcastListener;
    private boolean mIsActivityPaused = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mylayout);

        // Create the broadcast listener and register the filters
        mIsActivityPaused = false;
        mBroadcastListener = new BroadcastListener();

        IntentFilter filter = new IntentFilter();
        filter.addAction(Params.INTENT_REFRESH);
        filter.addAction(Params.INTENT_UPDATE);
        registerReceiver(mBroadcastListener, filter);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mIsActivityPaused = false;
    }

    @Override
    protected void onPause() {
        super.onPause();
        mIsActivityPaused = true;
    }

    @Override
    protected void onDestroy() {
        unregisterReceiver(mBroadcastListener);
        super.onDestroy();
    }

    private void refresh() {
        // refresh
    }

    private void update() {
        // update
    }

    private class BroadcastListener extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Params.INTENT_REFRESH && !mIsActivityPaused)) {
                refresh();
            } else if (intent.getAction().equals(Params.INTENT_UPDATE)) {
                update();
            }
        }
    }
}

I want to execute refresh() only if my Activity is visible on the screen, but I want to catch INTENT_UPDATE and execute update() during the entire lifetime of the Activity, regardless of whether the Activity is visible or not.

I didn't find any way to unregister only one of the two filters that I register in onCreate, so I use a flag to enable or disable the action to be executed when the INTENT_REFRESH broadcast is caught, depending on the state of the Activity.

The question is: is this the correct approach?

Or, would it be better to have two separate BroadcastReceivers as follows:

public class MyActivity extends Activity {
    private MyActivity.BroadcastListenerRefresh mBroadcastListenerRefresh;
    private MyActivity.BroadcastListenerUpdate mBroadcastListenerUpdate;
    private boolean mIsBroadcastListenerRefreshRegistered = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Create the broadcast listeners
        mBroadcastListenerRefresh = new BroadcastListenerRefresh();
        mBroadcastListenerUpdate = new BroadcastListenerUpdate();

        registerReceiver(mBroadcastListenerRefresh, new IntentFilter(Params.INTENT_REFRESH));
        registerReceiver(mBroadcastListenerUpdate, new IntentFilter(Params.INTENT_UPDATE));
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mBroadcastListenerRefresh != null && !mIsBroadcastListenerRefreshRegistered) {
            registerReceiver(mBroadcastListenerRefresh, new IntentFilter(Params.INTENT_REFRESH));
            mIsBroadcastListenerRefreshRegistered = true;
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mBroadcastListenerRefresh != null && mIsBroadcastListenerRefreshRegistered) {
            unregisterReceiver(mBroadcastListenerRefresh);
            mIsBroadcastListenerRefreshRegistered = false;
        }
    }

    @Override
    protected void onDestroy() {
        unregisterReceiver(mBroadcastListenerRefresh);
        unregisterReceiver(mBroadcastListenerUpdate);
        super.onDestroy();
    }

    private void refresh() {
        // refresh
    }

    private void update() {
        // update
    }

    private class BroadcastListenerRefresh extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Params.INTENT_REFRESH)) {
                refresh();
            }
        }
    }

    private class BroadcastListenerUpdate extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Params.INTENT_UPDATE)) {
                update();
            }
        }
    }
}

And which one has better performance?

Lorenzo Polidori
  • 10,332
  • 10
  • 51
  • 60

3 Answers3

239

instead, you may provide two different intent filters:

filter for refresh only

IntentFilter filterRefresh = new IntentFilter(Params.INTENT_REFRESH);

filter for refresh and update

IntentFilter filterRefreshUpdate = new IntentFilter();
filterRefreshUpdate.addAction(Params.INTENT_REFRESH);
filterRefreshUpdate.addAction(Params.INTENT_UPDATE);

now you may switch between intent filters by registering and un-registering the desired one but your receiver's implementation would be same

wdziemia
  • 1,429
  • 1
  • 14
  • 19
waqaslam
  • 67,549
  • 16
  • 165
  • 178
  • @Waqas Can you provide an example implementation of the BroadcastReceiver that would receive multiple intents? Is it just a big if-then-else statement? – gonzobrains May 08 '13 at 23:01
  • 2
    @gonzobrains yes, for multiple intents you need to use equal number of if-else statements to filter them out – waqaslam May 08 '13 at 23:10
  • @Waqas Is there a way to do this dynamically so that you have a generic broadcast receiver and can add multiple handlers to it so as to not have to modify the basic framework each time you add a new intent to it? – gonzobrains May 08 '13 at 23:28
  • what do you exactly mean by **"to do this dynamically"**? Simply include all the action strings inside your intent-filters and perform if-else to identify your required action strings. – waqaslam May 09 '13 at 10:22
  • 3
    I don't understand all the upvotes for this answer. For what the op was trying to do, it seems that 1 intent filter with 2 actions is adequate. The code in the first code block in the question seems to be all that's needed. – hBrent Jul 11 '17 at 15:41
  • @hBrent Same here. It seems that the provided solution is exactly what OP tried to do in his first code block, only with the added complexity of unregistering and registering them each time. – Big_Chair Feb 01 '18 at 18:25
30

For every action , create IntentFilter and register it.

@Override
protected void onResume() {

    super.onResume();

    BroadcastListener receiver = new BroadcastListener();

    // Register the filter for listening broadcast.
    IntentFilter filterRefresh = new IntentFilter(Params.INTENT_REFRESH);
    IntentFilter filterUpdate = new IntentFilter(Params.INTENT_UPDATE);

    registerReceiver(receiver, filterRefresh);
    registerReceiver(receiver, filterUpdate);
} 



private class BroadcastListener extends BroadcastReceiver {
    public void onReceive(Context ctx, Intent intent) {

        if (intent.getAction().equals(Params.INTENT_UPDATE)) {
            update();
        } else if(intent.getAction().equals(Params.INTENT_REFRESH)) {
            refresh();
        }
    }

}
Pawan Yadav
  • 1,772
  • 19
  • 17
  • 4
    Shouldn't I be worried calling `registerReceiver` multiple times and invoking `unregisterReceiver` one time only? – mr5 Aug 11 '15 at 08:06
  • 3
    If u call registerReceiver multiple time and unregisterReceiver only one time then previous instance of receiver might leak. So the instance u register then using that instance for unregister. – Pawan Yadav Aug 11 '15 at 14:23
  • 2
    If you were to register multiple times on the same action, then I'd say you should be worried. – stdout Dec 23 '15 at 08:36
  • 1
    Shouldn't this be discouraged? It'd be helpful for Google devs to throw an exception when you register the same BroadcastReceiver more than once. Instead we should add multiple actions to the intent filter. – TheRealChx101 Sep 22 '18 at 10:51
9

Using KOTLIN you can do it inline:

  broadcastReceiver = NukeBroadcastReceiver()
        registerReceiver(broadcastReceiver, IntentFilter().apply {
            addAction(ACTION_DESTROY_EVERYTHING)
            addAction(ACTION_RESTART_WORLD)
        })
Hitesh Sahu
  • 41,955
  • 17
  • 205
  • 154