2013-05-07 67 views
2

我知道如何檢測耳機插頭事件,如果我的應用程序正在運行。您必須爲ACTION_HEADSET_PLUG註冊廣播接收器。但是,您無法使用廣播接收器的清單聲明來捕獲此操作。因此,捕獲耳機插入事件的唯一選擇是後臺服務。但它消耗電池等等。如何檢測「離線」模式下的耳機插頭事件

我查了一些音樂播放器,發現他們沒有任何附加服務就捕獲該事件。他們如何做到這一點?有任何想法嗎?

+0

「我檢查了一些音樂播放器,發現它們沒有任何附加服務就捕獲了該事件」 - 命名任何能夠捕獲此事件而沒有運行代碼的名稱。 – CommonsWare 2013-05-07 00:30:48

+0

「我檢查了一些音樂播放器,發現它們沒有任何附加服務就捕獲了該事件。」你是怎麼弄出來的?是否因爲這些應用程序中沒有出現在最近的應用程序中?因爲如果是這樣,那可以很容易地完成。 – 2013-05-07 00:47:49

+0

「爲任何能夠捕獲此事件而沒有運行代碼的名稱。」功率放大器 – MistaGreen 2013-05-07 04:05:55

回答

8

我已經在商店裏有一個應用程序三年,既監控有線耳機和藍牙狀態,也沒有人抱怨電池耗盡。但那是因爲我成功地使用單個服務和廣播接收機來檢測來自兩者的事件。這裏有兩個關鍵類:

public class HeadsetStateBroadcastReceiver extends BroadcastReceiver { 

    public static final String[] HEADPHONE_ACTIONS = { 
     Intent.ACTION_HEADSET_PLUG, 
     "android.bluetooth.headset.action.STATE_CHANGED", 
     "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED" 
    }; 

    @Override 
    public void onReceive(final Context context, final Intent intent) { 

     boolean broadcast = false; 

     // Wired headset monitoring 
     if (intent.getAction().equals(HEADPHONE_ACTIONS[0]) { 
      final int state = intent.getIntExtra("state", 0); 
      AudioPreferences.setWiredHeadphoneState(context, state > 0); 
      broadcast = true; 
     } 

     // Bluetooth monitoring 
     // Works up to and including Honeycomb 
     if (intent.getAction().equals(HEADPHONE_ACTIONS[1])) { 
      int state = intent.getIntExtra("android.bluetooth.headset.extra.STATE", 0); 
      AudioPreferences.setBluetoothHeadsetState(context, state == 2); 
      broadcast = true; 
     } 

     // Works for Ice Cream Sandwich 
     if (intent.getAction().equals(HEADPHONE_ACTIONS[2])) { 
      int state = intent.getIntExtra("android.bluetooth.profile.extra.STATE", 0); 
      AudioPreferences.setBluetoothHeadsetState(context, state == 2); 
      broadcast = true; 
     } 

     // Used to inform interested activities that the headset state has changed 
     if (broadcast) { 
      LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("headsetStateChange")); 
     } 

    } 

} 

下面是我用註冊的廣播接收器的服務:

public class HeadsetMonitoringService extends Service { 

    HeadsetStateBroadcastReceiver headsetStateReceiver; 

    @Override 
    public void onCreate() { 

     headsetStateReceiver = new HeadsetStateBroadcastReceiver(); 
     final IntentFilter filter = new IntentFilter(); 
     for (String action: HeadsetStateBroadcastReceiver.HEADPHONE_ACTIONS) { 
      filter.addAction(action); 
     } 

     registerReceiver(headsetStateReceiver, filter); 

    } 

    @Override 
    public int onStartCommand(final Intent intent, final int flags, final int startId) { 
     return START_STICKY; 
    } 

    @Override 
    public void onDestroy() { 
     unregisterReceiver(headsetStateReceiver); 
    } 

    @Override 
    public IBinder onBind(final Intent intent) { 
     return null; 
    } 

} 

這裏是我的清單條目:

<service 
     android:name=".services.HeadsetMonitoringService" 
     android:enabled="true" 
     android:exported="false" > 
     <intent-filter> 
      <action android:name="initialiseHeadsetService" /> 
     </intent-filter> 
    </service> 

它是如何工作如下:

我在啓動時使用br oadcast接收器將啓動服務消息發送到HeadsetMonitoringService(您不必這樣做,您可以在應用程序啓動時執行此操作)。 HeadsetMonitoringService反過來註冊一個監聽我感興趣的所有耳機​​事件的廣播監聽器的實例 - 它們被保存在HEADPHONE_ACTIONS數組中。因爲服務很粘滯,所以廣播監聽者也是如此。但是因爲服務和廣播監聽器都是事件驅動的,所以在耳機狀態改變發生之前它們不消耗任何電力。此外,由於該服務很粘,如果操作系統意外死亡,它將被操作系統重新啓動。
每當我收到一個耳機狀態改變事件時,我也會啓動一個本地廣播,以便感興趣的活動可以檢查新狀態並在需要時採取措施。

爲了完整起見,我要指出,我用另一個類(這裏沒有顯示),AudioPreferences,以存儲爲喜好都藍牙和有線耳機的狀態,每當我需要知道耳機的狀態,然後可以訪問。

如果您對藍牙耳機的狀態感興趣,則您的應用程序將需要android.permission.BLUETOOTH權限。如果不是,只需從HEADPHONE_ACTIONS數組中取出藍牙相關的操作,並從onReceive方法中刪除關聯的if塊。

+0

我已經實施了非常類似的解決方案,但忘記在這裏發佈。現在一切都很完美。謝謝菲爾! – MistaGreen 2013-09-30 23:09:38