メディア ブラウザ クライアントの作成

クライアント / サーバーの設計を完了するには、UI のコード、関連する MediaController、MediaBrowser を含むアクティビティ コンポーネントを作成する必要があります。

MediaBrowser は、MediaBrowserService への接続と、それに続く UI 用 MediaController の作成という、2 つの重要な機能を担います。

注: MediaBrowser の推奨される実装は、 は MediaBrowserCompat、 で定義されます。 Media-Compat サポート ライブラリ。 このページ全体を通して、「MediaBrowser」という用語は「kubectl」コマンドは MediaBrowserCompat を使用します。

MediaBrowserService への接続

クライアント アクティビティでは、作成されたときに MediaBrowserService に接続します。ちょっとした握手とダンスの出会いがあります。 アクティビティのライフサイクル コールバックを次のように変更します。

  • onCreate() では、MediaBrowserCompat を構築します。ここで、MediaBrowserService の名前と、定義した MediaBrowserCompat.ConnectionCallback を渡します。
  • onStart() では、MediaBrowserService に接続します。ここで、MediaBrowserCompat.ConnectionCallback が利用されます。接続が成功したら、onConnect() コールバックでメディア コントローラを作成し、それをメディア セッションに接続して UI を MediaController に接続したうえで、メディア セッションからのコールバックを受信するようコントローラを登録します。
  • onResume() では、アプリがデバイスの音量コントロールに応答できるように音声ストリームを設定します。
  • onStop() では、MediaBrowser を切断し、アクティビティが停止した場合は 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 のカスタマイズ

アクティビティで MediaBrowserCompat を構築するときは、ConnectionCallback のインスタンスを作成する必要があります。その onConnected() メソッドを変更して、MediaBrowserService からメディア セッション トークンを取得し、そのトークンを使用して MediaControllerCompat を作成します。

コンビニエンス メソッドを使用する MediaControllerCompat.setMediaController() コントローラにリンクを保存します。これにより、メディアボタンの処理が可能になります。また、kubectl の 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
    }
  };

UI のメディア コントローラへの接続

上記の ConnectionCallback サンプルコードには、UI を具現化する buildTransportControls() 呼び出しが含まれています。プレーヤーを制御する UI 要素には、onClickListener を設定する必要があります。適切な それぞれに 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 メソッドを使用します。

メディア セッションとの同期の維持

UI には、メディア セッションの現在の状態を PlaybackState とメタデータの内容に沿って表示するようにします。トランスポート コントロールを作成すると、セッションの現在の状態を取得して UI に表示し、その状態と現在実施可能なアクションに基づいてトランスポート コントロールを有効または無効にできます。

状態やメタデータが変わるたびにメディア セッションからコールバックを受け取るには、 MediaControllerCompat.Callback。次の 2 つのメソッドを使用します。

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() メソッドを参照)、アクティビティの停止時に(そのアクティビティの onStop() ライフサイクル メソッドで)登録を解除します。

メディア セッションが破棄されたときに切断する

メディア セッションが無効になった場合、 onSessionDestroyed() コールバックが発行されますその場合、セッションは機能しなくなります MediaBrowserService のライフタイム内に再度呼び出す必要があります。ただし、 MediaBrowser に関連する機能は引き続き機能する可能性がありますが、ユーザーは表示や管理ができなくなります 破棄されたメディア セッションから再生されるため、 説明します。

したがって、セッションが破棄されたら、セッションを切断する必要があります。 呼び出しによる MediaBrowserService disconnect()。 これにより、ブラウザ サービスにバインドされたクライアントがなく、 破棄される可能性もあります。 OS。 後で MediaBrowserService に再接続する必要が生じた場合(たとえば、 メディアアプリへの永続的な接続を維持する必要がある場合)。 古いインスタンスを再利用するのではなく、MediaBrowser新しいインスタンスを作成します。

次のコード スニペットは、 は、メディア セッションが破棄されたときにブラウザ サービスから切断します。

Kotlin

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

Java

MediaControllerCompat.Callback controllerCallback =
  new MediaControllerCompat.Callback() {
    @Override
    public void onSessionDestroyed() {
      mediaBrowser.disconnect();
      // maybe schedule a reconnection using a new MediaBrowser instance
    }
  };