Search code examples
javaandroidbroadcastreceiverandroid-broadcast

How to respond once to multiple broadcasts? Jelly Bean LG sending two broadcasts for one event


I'm using some working code I found here within a service for detecting headphone connection state via ACTION_HEADSET_PLUG. I have two phones for testing, a Gingerbread Motorola and a Jelly Bean LG. On the Gingerbread phone everything works fine...i plug in headphones and I get one broadcast from Android and then I execute my work. On the Jelly Bean phone I'm getting two(2) broadcasts for every headphone state change and consequently my own stuff is then called twice. I'm not 100% certain but I don't think this is related to sticky broadcasts as if that were the case I should see the same behavior on both Gingerbread and Jellybean phones.

Filtering all system logcat msgs for "headset_plug" on the Jelly Bean phone I'll see something like this on a headset state change:

02-01 07:39:11.983: I/MusicBrowser(1739): [MediaPlaybackService.java:mHeadsetReceiver.onReady()] oooooo intentIntent { act=android.intent.action.HEADSET_PLUG flg=0x40000010 (has extras) }
02-01 07:39:12.083: I/MusicBrowser(1739): [MediaPlaybackService.java:mHeadsetReceiver.onReady()] oooooo intentIntent { act=android.intent.action.HEADSET_PLUG flg=0x40000010 (has extras) }

I could be mistaken but everything seems like this phone is sending two broadcasts within microseconds of each other whereas the Gingerbread Motorola is only sending one. I don't know if this is an Android bug, an intentional change between versions, an issue with this specific LG phone or what but it seems I need a way to respond only one time when the same broadcast is sent out multiple times.


Solution

  • Just in case anyone comes later w/ the same problem...

    I couldn't figure out how to deal with multiple broadcasts using boolean values for the state but I did solve this by setting an integer for the state. If the service receives multiple broadcasts for "unplugged" it will always set the int lastHeadsetState to 0. If it receives multiple broadcasts for plugged the first broadcast will set lastHeadsetState to 1 and additional broadcasts will increment lastHeadsetState by 1. I then check if lastHeadsetState equals exactly 1 and then do my work. Any value other than 1 implies multiple broadcasts were received and should be ignored.

    So here's my code for service that listens for headphone plug/unplug state changes, ignores the initial sticky broadcasts generated when the service is launched and contains logic to tolerate multiple broadcasts from wacky hardware. If anyone cares to suggest a more elegant way to achieve the same result I'd be interested. Apologies for any formatting errors below:

    public class HeadsetService extends Service{
    
    private static final String TAG = "HeadsetService";
    private HeadsetReceiver hReceiver;
    private int lastHeadsetState;
    
    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }
    
    @Override
    public void onCreate() {
    
        super.onCreate();       
        hReceiver = new HeadsetReceiver();
    
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Register a new HeadsetReceiver       
        IntentFilter hfilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);    
        registerReceiver(hReceiver, hfilter);
    
    return START_STICKY;}
    
     private class HeadsetReceiver extends BroadcastReceiver {
    
    @Override
    public void onReceive(Context context, Intent intent) {
    
        if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
    
            // ignore the initial sticky broadcast when the service starts
            if (isInitialStickyBroadcast()) {
            } 
    
            else { 
    
            int state = intent.getIntExtra("state", -1);
            switch (state) {
            case 0:             
                Log.d(TAG, "headset unplugged");
                //set lastHeadsetState to 0 for later comparison
            lastHeadsetState = 0;               
                Log.d(TAG, "lastHeadsetState set to 0");
    
            break;
            case 1:                             
                Log.d(TAG, "headset plugged in!");
                lastHeadsetState = (lastHeadsetState + 1);
                Log.d(TAG, "lastHeadsetState incremented by 1");
                //check if lastHeadsetState is exactly 1...any greater value means multiple broadcasts were received.
                if (lastHeadsetState == 1) {
            //do whatever you're going to do when the headset is plugged in here                   
    
            Log.d(TAG, "Headset state has changed from unplugged to plugged");
                }
                 else 
                     Log.d(TAG, "Multiple broadcasts received, ignoring duplicates");
    
            break; 
            default:
                Log.w("uh", "I have no idea what the headset state is");
                }   
              }
           }
         }
       }
     }