Building a media browser client(构建媒体浏览器客户端)
GitHub 链接
译:https://developer.android.com/guide/topics/media-apps/audio-app/building-a-mediabrowser-client
要完成 client / server 设计,你必须构建一个 Activity 组件,它包含你的 UI 代码、关联的 MediaController 和 MediaBrowser。
MediaBrowser 执行两个重要的功能: 它连接到 MediaBrowserService,并在连接时为你的 UI 创建 MediaController。
Note: MediaBrowser 的推荐实现是 MediaBrowserCompat ,该类被定义在 Media-Compat support library 中。在本文中 术语 “MediaBrowser” 指的是 MediaBrowserCompat 的实例。
Connect to the MediaBrowserService
创建客户端 Activity 后,它将连接到 MediaBrowserService 。有一点需要提醒,修改 Activity 的生命周期回调,如下所示:
-
onCreate()
构造一个 MediaBrowserCompat,传递你已定义的 MediaBrowserService 和 MediaBrowserCompat.ConnectionCallback 。 -
onStart()
连接到 MediaBrowserService。如果连接成功,自己需要手动在 ConnectionCallback 的onConnected()
回调里去创建 media controller,将其链接到 media session,将 UI 控件链接到 MediaController,and registers the controller to receive callbacks from the media session. -
onResume()
设置音频流,以便你的应用响应设备上的音量控制 -
onStop()
断开 MediaBrowser,并在 Activity stop 时取消注册 MediaController.Callback 。
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();
}
}
Customize MediaBrowserCompat.ConnectionCallback
当你的 Activity 构造 MediaBrowserCompat 时,你必须创建 ConnectionCallback 的实例。修改其 onConnected
方法,检索来自MediaBrowserService
的 media session token,并使用该 token 创建 MediaControllerCompat
。
使用便捷方法 MediaControllerCompat.setMediaController() 来保存 controller 的引用。这样可以处理 media buttons 。它还允许你在构建 transport controls 时调用 MediaControllerCompat.getMediaController() 来获取 controller。
下面的代码示例展示了如何修改 onConnected()
方法。
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
}
};
Connect your UI to the media controller
在上面的 ConnectionCallback
示例代码中,包含对 buildTransportControls()
的调用以充实你的 UI。你需要为控制播放器的 UI 元素设置 onClickListeners
。为每个元素选择适当的 MediaControllerCompat.TransportControls 方法。
你的代码看起来像这样,每个按钮都有一个 onClickListener:
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);
}
}
The TransportControls methods send callbacks to your service’s media session. Make sure you’ve defined a corresponding MediaSessionCompat.Callback method for each control.
Stay in sync with the media session
UI 应显示 media session 的当前状态,如其 PlaybackState 和 Metadata 所述。当你创建 transport controls 时,你可以获取 session 的当前状态,在 UI 中显示它,并根据状态及其可用的操作 启用和禁用 transport controls。
为了在每次状态或元数据发生改变时,能从 media session 接收回调。请定义一个 MediaControllerCompat.Callback :
MediaControllerCompat.Callback controllerCallback =
new MediaControllerCompat.Callback() {
@Override
public void onMetadataChanged(MediaMetadataCompat metadata) {}
@Override
public void onPlaybackStateChanged(PlaybackStateCompat state) {}
};
在构建 transport controls 注册回调(请参阅上面的 buildTransportControls()
),并在 Activity stop 时取消注册(在 Activity 的 onStop()
生命周期方法中)