Untuk melengkapi desain klien/server, Anda harus membuat komponen aktivitas yang berisi kode UI, MediaController yang terkait, dan MediaBrowser.
MediaBrowser melakukan dua fungsi penting: Membuat sambungan ke MediaBrowserService dan, setelah tersambung, membuat MediaController untuk UI Anda.
Catatan: Penerapan MediaBrowser yang direkomendasikan
adalah MediaBrowserCompat
,
yang didefinisikan dalam
Support library Media-Compat.
Di sepanjang halaman ini, istilah "MediaBrowser" merujuk ke instance
MediaBrowserCompat.
Membuat sambungan ke MediaBrowserService
Saat aktivitas klien Anda dibuat, aktivitas tersebut akan tersambung ke MediaBrowserService. Sedikit penyesuaian perlu dilakukan di sini. Ubah callback siklus proses aktivitas sebagai berikut:
onCreate()
menyusun MediaBrowserCompat. Masukkan nama MediaBrowserService dan MediaBrowserCompat.ConnectionCallback yang telah ditetapkan.onStart()
terhubung ke MediaBrowserService. Di sinilah kecanggihan MediaBrowserCompat.ConnectionCallback berperan. Jika sambungan berhasil, callback onConnect() akan membuat pengontrol media, menautkannya ke sesi media, menautkan kontrol UI Anda ke MediaController, dan mendaftarkan pengontrol untuk menerima callback dari sesi media.onResume()
menetapkan aliran audio sehingga aplikasi Anda merespons kontrol volume di perangkat.onStop()
memutus sambungan MediaBrowser dan membatalkan pendaftaran MediaController.Callback saat aktivitas Anda berhenti.
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(); } }
Menyesuaikan MediaBrowserCompat.ConnectionCallback
Saat aktivitas Anda menyusun MediaBrowserCompat, Anda harus membuat instance ConnectionCallback. Modifikasi metode onConnected()
-nya untuk mengambil token sesi media dari MediaBrowserService, lalu gunakan token tersebut untuk membuat MediaControllerCompat.
Gunakan metode praktis
MediaControllerCompat.setMediaController()
untuk menyimpan
tautan ke {i>controller<i}. Hal ini memungkinkan penanganan tombol media. Hal ini juga memungkinkan
Anda untuk memanggil
MediaControllerCompat.getMediaController()
untuk mengambil pengontrol saat mem-build kontrol transport.
Contoh kode berikut menunjukkan cara memodifikasi metode 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 } };
Menyambungkan UI Anda ke pengontrol media
Dalam contoh kode ConnectionCallback di atas, sertakan panggilan ke buildTransportControls()
untuk menyempurnakan UI Anda. Anda harus menetapkan onClickListeners untuk elemen UI yang mengontrol pemutar. Pilih layanan yang sesuai
MediaControllerCompat.TransportControls
untuk setiap variabel.
Kode Anda akan terlihat seperti ini, dengan onClickListener untuk setiap tombol:
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); } }
Metode TransportControls mengirim callback ke sesi media layanan Anda. Pastikan Anda telah menetapkan
Metode MediaSessionCompat.Callback
untuk setiap kontrol.
Mempertahankan sinkronisasi dengan sesi media
UI harus menampilkan status sesi media saat ini, seperti yang dijelaskan oleh PlaybackState dan Metadata-nya. Saat membuat kontrol transport, Anda dapat mengambil status sesi saat ini, menampilkannya di UI aplikasi Anda, serta mengaktifkan dan menonaktifkan kontrol transport berdasarkan status dan tindakan yang tersedia.
Untuk menerima callback dari sesi media setiap kali status atau metadatanya berubah, tentukan
MediaControllerCompat.Callback
, dengan dua metode ini:
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) {} };
Daftarkan callback ini ketika Anda membuat kontrol transport (lihat metode buildTransportControls()
) dan batalkan pendaftarannya saat aktivitas berhenti (dalam metode siklus proses onStop()
aktivitas.
Putuskan koneksi saat sesi media dihancurkan
Jika sesi media menjadi tidak valid,
onSessionDestroyed()
akan dikeluarkan. Jika hal itu terjadi, sesi tidak dapat berfungsi
lagi selama masa pakai MediaBrowserService
. Meskipun fungsi
yang terkait dengan MediaBrowser
mungkin terus berfungsi, pengguna tidak dapat melihat atau mengontrol
pemutaran dari sesi media yang dihancurkan, yang kemungkinan akan mengurangi nilai
aplikasi Anda.
Oleh karena itu, saat sesi dihancurkan, Anda harus memutuskan sambungan dari
MediaBrowserService
dengan memanggil
disconnect()
.
Hal ini memastikan bahwa layanan {i>browser<i}
tidak memiliki klien terikat dan
dapat dihancurkan oleh
OS Anda.
Jika nanti Anda perlu menghubungkan kembali ke MediaBrowserService
(misalnya, jika
aplikasi Anda ingin mempertahankan koneksi persisten ke aplikasi media),
membuat instance baru dari MediaBrowser
, bukan menggunakan kembali yang lama.
Cuplikan kode berikut menunjukkan implementasi callback yang terputus dari layanan browser saat sesi media dihancurkan:
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 } };