Чтобы завершить проектирование клиента/сервера, вам необходимо создать компонент активности, содержащий код пользовательского интерфейса, связанный 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
}
};