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: Implementasi MediaBrowser yang direkomendasikan adalah MediaBrowserCompat, yang ditentukan dalam support library Media-Compat. Di sepanjang halaman ini, istilah "MediaBrowser" mengacu pada instance MediaBrowserCompat.

Membuat sambungan ke MediaBrowserService

Saat aktivitas klien Anda dibuat, aktivitas tersebut akan tersambung ke MediaBrowserService. Sedikit penyesuaian perlu dilakukan di sini. Modifikasi 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 link ke pengontrol. Hal ini memungkinkan penanganan tombol media. Anda juga dapat memanggil MediaControllerCompat.getMediaController() untuk mengambil pengontrol saat membuat 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 metode MediaControllerCompat.TransportControls yang sesuai untuk setiap elemen.

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 yang sesuai 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 metadata atau statusnya berubah, tentukan MediaControllerCompat.Callback dengan dua metode berikut:

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.