Чтобы завершить проектирование клиента/сервера, вам необходимо создать компонент действия, содержащий код пользовательского интерфейса, связанный MediaController и MediaBrowser.
MediaBrowser выполняет две важные функции: он подключается к MediaBrowserService и после подключения создает MediaController для вашего пользовательского интерфейса.
Примечание. Рекомендуемой реализацией MediaBrowser является MediaBrowserCompat
, которая определена в библиотеке поддержки Media-Compat . На этой странице термин «MediaBrowser» относится к экземпляру MediaBrowserCompat.
Подключитесь к MediaBrowserService.
Когда ваша клиентская активность создается, она подключается к MediaBrowserService. Это небольшое рукопожатие и танец. Измените обратные вызовы жизненного цикла действия следующим образом:
-
onCreate()
создает MediaBrowserCompat. Передайте имя вашего MediaBrowserService и определенный вами MediaBrowserCompat.ConnectionCallback. -
onStart()
подключается к MediaBrowserService. Вот здесь-то и проявляется магия MediaBrowserCompat.ConnectionCallback. Если соединение установлено успешно, обратный вызов onConnect() создает медиа-контроллер, связывает его с медиа-сеансом, связывает ваши элементы управления пользовательского интерфейса с MediaController и регистрирует контроллер для получения обратных вызовов от медиа-сессия. -
onResume()
устанавливает аудиопоток, чтобы ваше приложение реагировало на регулятор громкости на устройстве. -
onStop()
отключает ваш MediaBrowser и отменяет регистрацию MediaController.Callback, когда ваша активность прекращается.
Котлин
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()
.
Котлин
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 } };
Подключите свой пользовательский интерфейс к медиаконтроллеру
В приведенном выше примере кода ConnectionCallback включен вызов buildTransportControls()
для конкретизации вашего пользовательского интерфейса. Вам нужно будет установить onClickListeners для элементов пользовательского интерфейса, которые управляют проигрывателем. Выберите соответствующий метод MediaControllerCompat.TransportControls
для каждого из них.
Ваш код будет выглядеть примерно так, с onClickListener для каждой кнопки:
Котлин
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
для каждого элемента управления.
Оставайтесь в курсе медиа-сессии
Пользовательский интерфейс должен отображать текущее состояние сеанса мультимедиа, как описано в его PlaybackState и метаданных. При создании элементов управления транспортом вы можете получить текущее состояние сеанса, отобразить его в пользовательском интерфейсе, а также включить и отключить элементы управления транспортом на основе состояния и доступных действий.
Чтобы получать обратные вызовы из медиа-сеанса каждый раз, когда его состояние или метаданные изменяются, определите MediaControllerCompat.Callback
с помощью этих двух методов:
Котлин
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
, а не повторно используйте старый.
Следующий фрагмент кода демонстрирует реализацию обратного вызова, который отключается от службы браузера при уничтожении медиа-сеанса:
Котлин
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 } };