Membuat klien browser media

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.
KotlinJava
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();

 
}
}

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().

KotlinJava
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
   
}
 
};

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:

KotlinJava
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);
}
}

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:

KotlinJava
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) {}
 
};

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:

KotlinJava
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
   
}
 
};