建立媒體瀏覽器用戶端

如要完成用戶端/伺服器設計,您必須建構包含 UI 程式碼、相關聯的 MediaController 和 MediaBrowser 的活動元件。

MediaBrowser 會執行兩個重要功能:連接至 MediaBrowserService,並在連線時建立使用者介面的 MediaController。

注意: 建議實作 MediaBrowser 是 MediaBrowserCompat, 定義位於 Media-Compat 支援資料庫。 在這個頁面中,「MediaBrowser」一詞參照執行個體 MediaBrowserCompat 的影像

連線至 MediaBrowserService

用戶端活動建立後,會連線至 MediaBrowserService。還有一點手握和舞蹈。 請按照下列步驟修改活動的生命週期回呼:

  • onCreate() 會建構 MediaBrowserCompat。傳入您定義的 MediaBrowserService 和 MediaBrowserCompat.ConnectionCallback 名稱。
  • onStart() 會連線至 MediaBrowserService。交給 MediaBrowserCompat.ConnectionCallback 的神奇功能吧。如果連線成功,onConnect() 回呼會建立媒體控制器、將其連結至媒體工作階段、將 UI 控制項連結至 MediaController,然後註冊控制器,以接收媒體工作階段的回呼。
  • onResume() 會設定音訊串流,以便應用程式回應裝置上的音量控制項。
  • onStop() 會中斷與 MediaBrowser 的連線,並在活動停止時取消註冊 MediaController.Callback。
KotlinJava
class MediaPlayerActivity : AppCompatActivity() {

   
private lateinit var mediaBrowser: MediaBrowserCompat

   
override fun onCreate(savedInstanceState: Bundle?) {
       
super.onCreate(savedInstanceState)
       
// ...
       
// Create MediaBrowserServiceCompat
        mediaBrowser
= MediaBrowserCompat(
               
this,
               
ComponentName(this, MediaPlaybackService::class.java),
                connectionCallbacks
,
               
null // optional Bundle
       
)
   
}

   
public override fun onStart() {
       
super.onStart()
        mediaBrowser
.connect()
   
}

   
public override fun onResume() {
       
super.onResume()
        volumeControlStream
= AudioManager.STREAM_MUSIC
   
}

   
public override fun onStop() {
       
super.onStop()
       
// (see "stay in sync with the MediaSession")
       
MediaControllerCompat.getMediaController(this)?.unregisterCallback(controllerCallback)
        mediaBrowser
.disconnect()
   
}
}
public class MediaPlayerActivity extends AppCompatActivity {
 
private MediaBrowserCompat mediaBrowser;

 
@Override
 
protected void onCreate(Bundle savedInstanceState) {
   
super.onCreate(savedInstanceState);
   
// ...
   
// Create MediaBrowserServiceCompat
    mediaBrowser
= new MediaBrowserCompat(this,
     
new ComponentName(this, MediaPlaybackService.class),
        connectionCallbacks
,
       
null); // optional Bundle
 
}

 
@Override
 
public void onStart() {
   
super.onStart();
    mediaBrowser
.connect();
 
}

 
@Override
 
public void onResume() {
   
super.onResume();
    setVolumeControlStream
(AudioManager.STREAM_MUSIC);
 
}

 
@Override
 
public void onStop() {
   
super.onStop();
   
// (see "stay in sync with the MediaSession")
   
if (MediaControllerCompat.getMediaController(MediaPlayerActivity.this) != null) {
     
MediaControllerCompat.getMediaController(MediaPlayerActivity.this).unregisterCallback(controllerCallback);
   
}
    mediaBrowser
.disconnect();

 
}
}

自訂 MediaBrowserCompat.ConnectionCallback

當活動建構 MediaBrowserCompat 時,您必須建立 ConnectionCallback 的執行個體。修改其 onConnected() 方法,以從 MediaBrowserService 擷取媒體工作階段權杖,並使用權杖建立 MediaControllerCompat。

使用便利方法 MediaControllerCompat.setMediaController() 儲存控制器的連結。這樣就能處理媒體按鈕。還能呼叫 MediaControllerCompat.getMediaController() 用於在建構傳輸控制項時擷取控制器。

以下程式碼範例說明如何修改 onConnected() 方法。

KotlinJava
private val connectionCallbacks = object : MediaBrowserCompat.ConnectionCallback() {
   
override fun onConnected() {

       
// Get the token for the MediaSession
        mediaBrowser
.sessionToken.also { token ->

           
// Create a MediaControllerCompat
           
val mediaController = MediaControllerCompat(
                   
this@MediaPlayerActivity, // Context
                    token
           
)

           
// Save the controller
           
MediaControllerCompat.setMediaController(this@MediaPlayerActivity, mediaController)
       
}

       
// Finish building the UI
        buildTransportControls
()
   
}

   
override fun onConnectionSuspended() {
       
// The Service has crashed. Disable transport controls until it automatically reconnects
   
}

   
override fun onConnectionFailed() {
       
// The Service has refused our connection
   
}
}
private final MediaBrowserCompat.ConnectionCallback connectionCallbacks =
 
new MediaBrowserCompat.ConnectionCallback() {
   
@Override
   
public void onConnected() {

     
// Get the token for the MediaSession
     
MediaSessionCompat.Token token = mediaBrowser.getSessionToken();

     
// Create a MediaControllerCompat
     
MediaControllerCompat mediaController =
       
new MediaControllerCompat(MediaPlayerActivity.this, // Context
        token
);

     
// Save the controller
     
MediaControllerCompat.setMediaController(MediaPlayerActivity.this, mediaController);

     
// Finish building the UI
      buildTransportControls
();
   
}

   
@Override
   
public void onConnectionSuspended() {
     
// The Service has crashed. Disable transport controls until it automatically reconnects
   
}

   
@Override
   
public void onConnectionFailed() {
     
// The Service has refused our connection
   
}
 
};

將 UI 連線至媒體控制器

在上方的 ConnectionCallback 程式碼範例中,加入對 buildTransportControls() 的呼叫,以完整顯示 UI。您需要為控製播放器的 UI 元素設定 onClickListener。選擇適當的設定 每種方法的 MediaControllerCompat.TransportControls 方法。

您的程式碼看起來會像這樣,每個按鈕都有一個 onClickListener:

KotlinJava
fun buildTransportControls() {
   
val mediaController = MediaControllerCompat.getMediaController(this@MediaPlayerActivity)
   
// Grab the view for the play/pause button
    playPause
= findViewById<ImageView>(R.id.play_pause).apply {
        setOnClickListener
{
           
// Since this is a play/pause button, you'll need to test the current state
           
// and choose the action accordingly

           
val pbState = mediaController.playbackState.state
           
if (pbState == PlaybackStateCompat.STATE_PLAYING) {
                mediaController
.transportControls.pause()
           
} else {
                mediaController
.transportControls.play()
           
}
       
}
   
}

   
// Display the initial state
   
val metadata = mediaController.metadata
   
val pbState = mediaController.playbackState

   
// Register a Callback to stay in sync
    mediaController
.registerCallback(controllerCallback)
}
void buildTransportControls()
{
 
// Grab the view for the play/pause button
  playPause
= (ImageView) findViewById(R.id.play_pause);

 
// Attach a listener to the button
  playPause
.setOnClickListener(new View.OnClickListener() {
   
@Override
   
public void onClick(View v) {
     
// Since this is a play/pause button, you'll need to test the current state
     
// and choose the action accordingly

     
int pbState = MediaControllerCompat.getMediaController(MediaPlayerActivity.this).getPlaybackState().getState();
     
if (pbState == PlaybackStateCompat.STATE_PLAYING) {
       
MediaControllerCompat.getMediaController(MediaPlayerActivity.this).getTransportControls().pause();
     
} else {
       
MediaControllerCompat.getMediaController(MediaPlayerActivity.this).getTransportControls().play();
     
}
 
});

 
MediaControllerCompat mediaController = MediaControllerCompat.getMediaController(MediaPlayerActivity.this);

 
// Display the initial state
 
MediaMetadataCompat metadata = mediaController.getMetadata();
 
PlaybackStateCompat pbState = mediaController.getPlaybackState();

 
// Register a Callback to stay in sync
  mediaController
.registerCallback(controllerCallback);
}
}

TransportControls 方法會將回呼傳送至服務的媒體工作階段。請務必先定義相應的 每個控制項的 MediaSessionCompat.Callback 方法。

與媒體工作階段保持同步

UI 應顯示媒體工作階段目前的狀態,如 PlaybackState 和 Metadata 所述。建立傳輸控制項時,您可以擷取工作階段目前的狀態並在 UI 中顯示該工作階段,並根據狀態和可用的動作啟用和停用傳輸控制項。

如要在媒體工作階段每次狀態或中繼資料變更時接收回呼,請定義 MediaControllerCompat.Callback,使用以下兩種方法:

KotlinJava
private var controllerCallback = object : MediaControllerCompat.Callback() {

   
override fun onMetadataChanged(metadata: MediaMetadataCompat?) {}

   
override fun onPlaybackStateChanged(state: PlaybackStateCompat?) {}
}
MediaControllerCompat.Callback controllerCallback =
 
new MediaControllerCompat.Callback() {
   
@Override
   
public void onMetadataChanged(MediaMetadataCompat metadata) {}

   
@Override
   
public void onPlaybackStateChanged(PlaybackStateCompat state) {}
 
};

在建立傳輸控制項時註冊回呼 (請參閱 buildTransportControls() 方法),並在活動停止時取消註冊 (在活動的 onStop() 生命週期方法中)。

在媒體工作階段刪除時中斷連線

如果媒體工作階段失效, onSessionDestroyed()敬上 回呼。在這種情況下,工作階段就無法正常運作 必須在 MediaBrowserService 生命週期內再次執行。雖然函式 與 MediaBrowser 相關的可能仍可繼續運作,使用者無法查看或控制 播放。 應用程式

因此,當工作階段遭到刪除時,您必須中斷與 撥號方式:MediaBrowserService disconnect()。 這可確保瀏覽器服務沒有繫結的用戶端,且 可能會遭到 作業系統。 如果您之後需要重新連線至 MediaBrowserService (例如 應用程式想要持續與媒體應用程式連線), 建立 MediaBrowser例項,而不是重複使用舊的例項。

下列程式碼片段示範的回呼實作會 當媒體工作階段刪除時,瀏覽器服務也會中斷連線:

KotlinJava
private var controllerCallback = object : MediaControllerCompat.Callback() {
   
override fun onSessionDestroyed() {
      mediaBrowser
.disconnect()
     
// maybe schedule a reconnection using a new MediaBrowser instance
   
}
}
MediaControllerCompat.Callback controllerCallback =
 
new MediaControllerCompat.Callback() {
   
@Override
   
public void onSessionDestroyed() {
      mediaBrowser
.disconnect();
     
// maybe schedule a reconnection using a new MediaBrowser instance
   
}
 
};