要完成客户端/服务器设计,您必须构建包含界面代码、关联的 MediaController 和 MediaBrowser 的 Activity 组件。
MediaBrowser 执行两项重要功能:连接到 MediaBrowserService,并在连接后为您的界面创建 MediaController。
注意:MediaBrowser 的建议实现方式是 MediaBrowserCompat
,它在 Media-Compat 支持库中定义。在本页中,术语“MediaBrowser”是指 MediaBrowserCompat 的一个实例。
连接到 MediaBrowserService
创建客户端 Activity 后,它会连接到 MediaBrowserService。这里涉及一点握手和跳跃。修改 Activity 的生命周期回调,如下所示:
onCreate()
构造 MediaBrowserCompat。传入您的 MediaBrowserService 的名称和您已定义的 MediaBrowserCompat.ConnectionCallback。onStart()
连接到 MediaBrowserService。这里体现了 MediaBrowserCompat.ConnectionCallback 的神奇之处。如果连接成功,onConnect() 回调会创建媒体控制器,将其链接到媒体会话,将您的界面控件链接到 MediaController,并注册控制器以接收来自媒体会话的回调。onResume()
设置音频流,以便您的应用响应设备上的音量控制。onStop()
断开 MediaBrowser 的连接,并在 Activity 停止时取消注册 MediaController.Callback。
Kotlin
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() } }
Java
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
当您的 Activity 构造 MediaBrowserCompat 时,您必须创建 ConnectionCallback 的实例。修改其 onConnected()
方法以从 MediaBrowserService 检索媒体会话令牌,并使用该令牌创建 MediaControllerCompat。
使用便捷方法 MediaControllerCompat.setMediaController()
保存指向控制器的链接,以便处理媒体按钮。您还可利用此方法在构建传输控件时调用 MediaControllerCompat.getMediaController()
来检索控制器。
以下代码示例演示了如何修改 onConnected()
方法。
Kotlin
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 } }
Java
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 } };
将您的界面连接到媒体控制器
在上面的 ConnectionCallback 示例代码中,包含对 buildTransportControls()
的调用以充实您的界面。您需要为控制播放器的界面元素设置 onClickListeners。为每一个元素选择合适的 MediaControllerCompat.TransportControls
方法。
您的代码将如下所示,每个按钮都有一个 onClickListener:
Kotlin
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) }
Java
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
方法。
与媒体会话保持同步
界面应显示媒体会话的当前状态(通过其 PlaybackState 和元数据来描述)。创建传输控件时,您可以抓取会话的当前状态,将其显示在界面中,并根据状态及其可用操作启用和停用传输控件。
要在媒体会话的状态或元数据每次发生更改时从媒体会话接收回调,请使用以下两种方法定义 MediaControllerCompat.Callback
:
Kotlin
private var controllerCallback = object : MediaControllerCompat.Callback() { override fun onMetadataChanged(metadata: MediaMetadataCompat?) {} override fun onPlaybackStateChanged(state: PlaybackStateCompat?) {} }
Java
MediaControllerCompat.Callback controllerCallback = new MediaControllerCompat.Callback() { @Override public void onMetadataChanged(MediaMetadataCompat metadata) {} @Override public void onPlaybackStateChanged(PlaybackStateCompat state) {} };
在构建传输控件时注册回调(请参阅 buildTransportControls()
方法),并在 Activity 停止时(在 Activity 的 onStop()
生命周期方法中)取消注册回调。