媒體按鈕是Android裝置和其他外圍裝置上的硬體按鈕,例如藍芽耳機上的暫停/播放按鈕。當使用者按下媒體按鈕時,Android會生成一個KeyEvent,其中包含一個識別按鈕的金鑰程式碼。media button KeyEvents的關鍵程式碼是以KEYCODE_MEDIA
開頭的常量(例如,KEYCODE_MEDIA_PLAY
)。
應用程式應該能夠在三種情況下處理媒體按鈕事件,按優先順序排列:
- 當應用程式的UI活動可見時
- 當UI活動隱藏且應用程式的媒體會話處於活動狀態時
- 當UI活動被隱藏,應用程式的媒體會話不活躍,需要重新啟動時
處理前臺活動中的媒體按鈕
前臺活動在其onKeyDown()
方法中接收media button key事件。根據Android的執行版本,系統有兩種方式將事件路由到媒體控制器:
- 如果你執行的是安卓5.0 (API level 21)或更高版本,呼叫FLAG_HANDLES_MEDIA_BUTTONS
MediaBrowserCompat.ConnectionCallback.onConnected
。這將自動呼叫您的媒體控制器的dispatchMediaButtonEvent(),它將關鍵程式碼轉換為媒體會話回撥。 - 在Android 5.0 (API level 21)之前,您需要修改onKeyDown()來自己處理事件。(有關詳細資訊,請參閱Handling media buttons in an active media session。)下面的程式碼片段展示瞭如何截獲關鍵程式碼並呼叫dispatchMediaButtonEvent()。確保返回true以指示事件已處理:
@Override
boolean onKeyDown(int keyCode, KeyEvent event) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return super.onKeyDown(keyCode, event);
}
switch (keyCode) {
case KeyEvent.KEYCODE_MEDIA_PLAY:
yourMediaController.dispatchMediaButtonEvent(event);
return true;
}
return super.onKeyDown(keyCode, event);
}
複製程式碼
尋找媒體會話
如果前臺活動不處理事件,Android將嘗試找到一個可以處理它的媒體會話。同樣,根據Android的執行版本,有兩種方法可以搜尋媒體會話:
- 如果你執行的是安卓8.0 (API level 26)或更高版本,系統會試圖找到最後一個帶有本地播放音訊的MediaSession的應用。如果會話仍然是活動的,Android會將事件直接傳送到它。否則,如果會話不是活動的,並且它有一個mediabutton接收器,Android將事件傳送給接收器,接收器將重新啟動會話,因此它可以接收事件。(有關詳細資訊,請參閱Using media buttons to restart an inactive media session 。)如果會話沒有媒體按鈕接收器,系統將丟棄媒體按鈕事件,並且什麼也不會發生。邏輯如下圖所示:
- 在Android 8.0 (API級別26)之前,系統嘗試將事件傳送到活動媒體會話。如果有多個活動媒體會話,Android會嘗試選擇準備播放(緩衝/連線)、播放或暫停的媒體會話,而不是停止的。(有關更多細節,請參見 Handling media buttons in an active media session。)如果沒有活動會話,Android會嘗試將事件傳送到最近的活動會話。(有關詳細資訊,請參閱使用Using media buttons to restart an inactive media session。)邏輯如下圖所示:
處理活動媒體會話中的媒體按鈕
在Android 5.0 (API level 21)及更高版本上,Android通過呼叫onMediaButtonEvent()自動將媒體按鈕事件分派給您的活動媒體會話。預設情況下,此回撥將KeyEvent轉換為與金鑰程式碼匹配的適當的媒體會話回撥方法。
在Android 5.0 (API level 21)之前,Android通過使用ACTION_MEDIA_BUTTON
操作廣播一個意圖來處理媒體按鈕事件。你的應用程式必須註冊一個廣播接收器來攔截這些意圖。MediaButtonReceiver類是專門為此目的設計的。它是Android media-compat庫中的一個方便類,它處理ACTION_MEDIA_BUTTON
並將傳入的意圖轉換為適當的MediaSessionCompat.Callback
方法呼叫。
MediaButtonReceiver
是一個短命的廣播接收器。它將傳入的意圖轉發給管理媒體會話的服務。如果你想在Android 5.0之前在系統中使用媒體按鈕,你必須在清單中包括MediaButtonReceiver
和MEDIA_BUTTON
意圖過濾器。
<receiver android:name="android.support.v4.media.session.MediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
複製程式碼
廣播接收器將意圖轉發給您的服務。要解析意圖並生成對媒體會話的回撥,請在服務的onStartCommand()
中包含MediaButtonReceiver.handleIntent()方法。這將把關鍵程式碼轉換為適當的會話回撥方法。
private MediaSessionCompat mMediaSessionCompat = ...;
public int onStartCommand(Intent intent, int flags, int startId) {
MediaButtonReceiver.handleIntent(mMediaSessionCompat, intent);
return super.onStartCommand(intent, flags, startId);
}
複製程式碼
注意:如果您沒有
MediaBrowserServiceCompat
,您還可以向任何服務新增ACTION_MEDIA_BUTTON
意圖過濾器。有關更多資訊,請參閱MediaButtonReceiver文件。
使用媒體按鈕重新啟動非活動的媒體會話
如果Android能夠識別最後一個活動媒體會話,它會試圖通過傳送一個ACTION_MEDIA_BUTTON意圖到一個宣告註冊的元件(如服務或廣播接收器)來重新啟動會話。
這可以讓你的應用在UI不可見時重啟回放,這是大多數音訊應用的情況。
當您使用MediaSessionCompat
時,將自動啟用此行為。如果你使用Android框架的MediaSession
或者Support Library 24.0.0到25.1.1
,你必須呼叫setMediaButtonReceiver
,讓媒體按鈕重新啟動一個非活動的媒體會話。
你可以通過設定一個空媒體按鈕接收器,在Android 5.0 (API級別21)或更高版本中禁用此行為:
// Create a MediaSessionCompat
mMediaSession = new MediaSessionCompat(context, LOG_TAG);
mMediaSession.setMediaButtonReceiver(null);
複製程式碼
注意:對於在Android 5.0 (API level 21)之前的系統中執行的應用程式,您註冊以處理活動會話的媒體按鈕的
MediaButtonReceiver
也會在會話不活動時接收媒體按鈕事件。無法禁用此行為。
定製媒體按鈕處理程式
onMediaButtonEvent()
的預設行為提取關鍵程式碼並使用媒體會話的當前狀態和支援的操作列表來確定呼叫哪個方法。例如,KEYCODE_MEDIA_PLAY
呼叫onPlay()
。
為了在所有應用程式中提供一致的媒體按鈕體驗,您應該使用預設行為,並且只為了特定的目的而偏離。如果媒體按鈕需要自定義處理,重寫回撥函式的onMediaButtonEvent()方法,使用intent.getparcelableextra (Intent.EXTRA_KEY_EVENT)提取KeyEvent
,自己處理事件,並返回true
。
總結
要正確處理Android所有版本中的媒體按鈕事件,必須在建立媒體會話時指定FLAG_HANDLES_MEDIA_BUTTONS。
此外,根據您計劃支援的Android版本,您還必須滿足以下要求:
執行Android 5.0或更高版本時:
- 從媒體控制器
onConnected()
回撥中呼叫MediaControllerCompat.setMediaController()
- 要允許媒體按鈕重新啟動非活動會話,可以通過呼叫
setMediaButtonReceiver()
並傳遞PendingIntent
動態建立MediaButtonReceiver
當系統執行時間早於Android 5.0時:
- 重寫活動的onKeyDown()以處理媒體按鈕
- 靜態建立一個
MediaButtonReceiver
通過新增它到應用程式的清單