Save the date! Android Dev Summit is coming to Mountain View, CA on November 7-8, 2018.

Building a media browser client

To complete the client/server design, you must build an activity component that contains your UI code, an associated MediaController, and a MediaBrowser.

The MediaBrowser performs two important functions: It connects to a MediaBrowserService, and upon connecting it creates the MediaController for your UI.

Note: The recommended implementation of MediaBrowser is MediaBrowserCompat, which is defined in the Media-Compat support library. Throughout this page the term "MediaBrowser" refers to an instance of MediaBrowserCompat.

Connect to the MediaBrowserService

When your client activity is created, it connects to the MediaBrowserService. There's a little handshake and dance involved. Modify the activity's lifecyle callbacks as follows:

  • onCreate() constructs a MediaBrowserCompat. Pass in the name of your MediaBrowserService and the MediaBrowserCompat.ConnectionCallback that you've defined.
  • onStart() connects to the MediaBrowserService. Here's where the magic of MediaBrowserCompat.ConnectionCallback comes in. If the connection is successful, the onConnect() callback creates the media controller, links it to the media session, links your UI controls to the MediaController, and registers the controller to receive callbacks from the media session.
  • onResume() sets the audio stream so your app responds to the volume control on the device.
  • onStop() disconnects your MediaBrowser and unregisters the MediaController.Callback when your activity stops.
public class MediaPlayerActivity extends AppCompatActivity {
  private MediaBrowserCompat mMediaBrowser;

  protected void onCreate(Bundle savedInstanceState) {
    // ...
    // Create MediaBrowserServiceCompat
    mMediaBrowser = new MediaBrowserCompat(this,
      new ComponentName(this, MediaPlaybackService.class),
        null); // optional Bundle

  public void onStart() {

  public void onResume() {

  public void onStop() {
    // (see "stay in sync with the MediaSession")
    if (MediaControllerCompat.getMediaController(MediaPlayerActivity.this) != null) {


Customize MediaBrowserCompat.ConnectionCallback

When your activity constructs MediaBrowserCompat, you must create an instance of ConnectionCallback. Modify its onConnected() method to retrieve the media session token from the MediaBrowserService and use the token to create a MediaControllerCompat.

Use the convenience method MediaControllerCompat.setMediaController() to save a link to the controller. This enables handling of media buttons. It also allows you to call MediaControllerCompat.getMediaController() to retrieve the controller when building the transport controls.

The following code sample shows how to modify the onConnected() method.

private final MediaBrowserCompat.ConnectionCallback mConnectionCallbacks =
  new MediaBrowserCompat.ConnectionCallback() {
    public void onConnected() {

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

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

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

      // Finish building the UI

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

    public void onConnectionFailed() {
      // The Service has refused our connection

Connect your UI to the media controller

In the ConnectionCallback sample code above, includes a call to buildTransportControls() to flesh out your UI. You'll need to set onClickListeners for the UI elements that control the player. Choose the appropriate MediaControllerCompat.TransportControls method for each one.

Your code will look something like this, with an onClickListener for each button:

void buildTransportControls()
  // Grab the view for the play/pause button
  mPlayPause = (ImageView) findViewById(;

  // Attach a listener to the button
  mPlayPause.setOnClickListener(new View.OnClickListener() {
    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) {
      } else {

  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

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

The UI should display the current state of the media session, as described by its PlaybackState and Metadata. When you create the transport controls, you can grab the current state of the session, display it in your UI, and enable and disable transport controls based on the state and its available actions.

To receive callbacks from the media session every time its state or metadata changes, define a MediaControllerCompat.Callback, with these two methods:

MediaControllerCompat.Callback controllerCallback =
  new MediaControllerCompat.Callback() {
    public void onMetadataChanged(MediaMetadataCompat metadata) {}

    public void onPlaybackStateChanged(PlaybackStateCompat state) {}

Register the callback when you build the transport controls (see the buildTransportControls() method) and unregister it when the activity stops (in the activity's onStop() lifecycle method).