Aplikasi media sering kali berisi koleksi item media, yang diatur dalam hierarki. Misalnya, lagu dalam album atau episode TV dalam playlist. Hierarki item media ini dikenal sebagai galeri media.
MediaLibraryService menyediakan API standar untuk menyajikan dan mengakses
galeri media Anda. Hal ini dapat berguna, misalnya, saat menambahkan dukungan untuk
Android Auto ke aplikasi media Anda, yang menyediakan UI yang aman bagi pengemudi untuk
galeri media Anda.
Membuat MediaLibraryService
Mengimplementasikan MediaLibraryService mirip dengan mengimplementasikan
MediaSessionService, kecuali bahwa dalam metode onGetSession(), Anda
harus menampilkan MediaLibrarySession, bukan MediaSession.
Kotlin
class PlaybackService : MediaLibraryService() { private var mediaLibrarySession: MediaLibrarySession? = null private val callback: MediaLibrarySession.Callback = object : MediaLibrarySession.Callback { /* ... */ } override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaLibrarySession? { // If desired, validate the controller before returning the media library session return mediaLibrarySession } // Create your player and media library session in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaLibrarySession = MediaLibrarySession.Builder(this, player, callback).build() } // Remember to release the player and media library session in onDestroy override fun onDestroy() { mediaLibrarySession?.run { player.release() release() mediaLibrarySession = null } super.onDestroy() } }
Java
class PlaybackService extends MediaLibraryService { MediaLibrarySession mediaLibrarySession = null; MediaLibrarySession.Callback callback = new MediaLibrarySession.Callback() { /* ... */ }; @Override public MediaLibrarySession onGetSession(MediaSession.ControllerInfo controllerInfo) { // If desired, validate the controller before returning the media library session return mediaLibrarySession; } // Create your player and media library session in the onCreate lifecycle event @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaLibrarySession = new MediaLibrarySession.Builder(this, player, callback).build(); } // Remember to release the player and media library session in onDestroy @Override public void onDestroy() { if (mediaLibrarySession != null) { mediaLibrarySession.getPlayer().release(); mediaLibrarySession.release(); mediaLibrarySession = null; } super.onDestroy(); } }
Service dan izin yang diperlukan dalam file manifes
juga:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaLibraryService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
Sebaiknya daftarkan layanan Anda sebagai platform dan antarmuka layanan Media3:
Untuk kompatibilitas dengan klien yang menggunakan API sesi media platform, sebaiknya sertakan
<action android:name="android.media.browse.MediaBrowserService"/>dalam elemenintent-filter. Media3 otomatis menyediakan kompatibilitas mundur ke antarmuka layanan ini.Sebagai penyiapan yang siap menghadapi masa depan dan untuk memastikan aplikasi yang menggunakan Media3 dapat berkomunikasi dengan layanan Anda menggunakan Media3 API,
<action android:name="androidx.media3.session.MediaLibraryService"/>harus disediakan bersama opsi platform.
Hal ini memungkinkan aplikasi menemukan layanan Anda melalui PackageManager dan terhubung
dengan MediaBrowser melalui salah satu antarmuka ini.
Menggunakan MediaLibrarySession
MediaLibraryService API mengharapkan galeri media Anda disusun dalam
format hierarki, dengan satu node root dan node turunan yang dapat
diputar atau dapat dijelajahi lebih lanjut.
MediaLibrarySession memperluas MediaSession API untuk menambahkan API penjelajahan konten. Dibandingkan dengan callback MediaSession, callback MediaLibrarySession menambahkan metode seperti:
onGetLibraryRoot()untuk saat klien meminta rootMediaItemdari hierarki kontenonGetChildren()untuk saat klien meminta turunan dariMediaItemdi hierarki kontenonGetSearchResult()saat klien meminta hasil penelusuran dari hierarki konten untuk kueri tertentu
Metode callback yang relevan akan menyertakan objek LibraryParams dengan
sinyal tambahan tentang jenis hierarki konten yang diminati
aplikasi klien.
Tombol perintah untuk item media
Aplikasi sesi dapat mendeklarasikan tombol perintah yang didukung oleh MediaItem di
MediaMetadata. Hal ini memungkinkan penetapan satu atau beberapa entri CommandButton
ke item media yang dapat ditampilkan dan digunakan pengontrol untuk mengirim perintah
kustom untuk item tersebut ke sesi dengan cara yang mudah.
Menyiapkan tombol perintah di sisi sesi
Saat membuat sesi, aplikasi sesi mendeklarasikan kumpulan tombol perintah yang dapat ditangani sesi sebagai perintah kustom:
Kotlin
val allCommandButtons = listOf( CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD) .setDisplayName(context.getString(R.string.add_to_playlist)) .setSessionCommand(SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setSessionCommand(SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build(), ) // Add all command buttons for media items supported by the session. val session = MediaSession.Builder(context, player) .setCommandButtonsForMediaItems(allCommandButtons) .build()
Java
ImmutableList<CommandButton> allCommandButtons = ImmutableList.of( new CommandButton.Builder(CommandButton.ICON_PLAYLIST_ADD) .setDisplayName(context.getString(R.string.add_to_playlist)) .setSessionCommand(new SessionCommand(COMMAND_PLAYLIST_ADD, Bundle.EMPTY)) .setExtras(playlistAddExtras) .build(), new CommandButton.Builder(CommandButton.ICON_RADIO) .setDisplayName(context.getString(R.string.radio_station)) .setSessionCommand(new SessionCommand(COMMAND_RADIO, Bundle.EMPTY)) .setExtras(radioExtras) .build()); // Add all command buttons for media items supported by the session. MediaSession session = new MediaSession.Builder(context, player) .setCommandButtonsForMediaItems(allCommandButtons) .build();
Saat membuat item media, aplikasi sesi dapat menambahkan kumpulan ID perintah yang didukung yang mereferensikan perintah sesi tombol perintah yang telah disiapkan saat membuat sesi:
Kotlin
val mediaItem = MediaItem.Builder() .setMediaMetadata( MediaMetadata.Builder() .setSupportedCommands(listOf(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build() ) .build()
Java
MediaItem mediaItem = new MediaItem.Builder() .setMediaMetadata( new MediaMetadata.Builder() .setSupportedCommands(ImmutableList.of(COMMAND_PLAYLIST_ADD, COMMAND_RADIO)) .build()) .build();
Saat pengontrol atau browser terhubung atau memanggil metode lain dari sesi
Callback, aplikasi sesi dapat memeriksa ControllerInfo yang diteruskan ke
callback untuk mendapatkan jumlah maksimum tombol perintah yang dapat ditampilkan
pengontrol atau browser. ControllerInfo yang diteruskan ke metode callback menyediakan
pengambil untuk mengakses nilai ini dengan mudah. Secara default, nilainya ditetapkan ke 0 yang
menunjukkan bahwa browser atau pengontrol tidak mendukung fitur ini:
Kotlin
override fun onGetItem( session: MediaLibrarySession, browser: MediaSession.ControllerInfo, mediaId: String, ): ListenableFuture<LibraryResult<MediaItem>> { val settableFuture = SettableFuture.create<LibraryResult<MediaItem>>() val maxCommandsForMediaItems = browser.maxCommandsForMediaItems loadMediaItemAsync(settableFuture, mediaId, maxCommandsForMediaItems) return settableFuture }
Java
@Override public ListenableFuture<LibraryResult<MediaItem>> onGetItem( MediaLibraryService.MediaLibrarySession session, ControllerInfo browser, String mediaId) { SettableFuture<LibraryResult<MediaItem>> settableFuture = SettableFuture.create(); int maxCommandsForMediaItems = browser.getMaxCommandsForMediaItems(); loadMediaItemAsync(settableFuture, mediaId, maxCommandsForMediaItems); return settableFuture; }
Saat menangani tindakan kustom yang telah dikirim untuk item media, aplikasi sesi
dapat memperoleh ID item media dari argumen Bundle yang diteruskan ke
onCustomCommand:
Kotlin
override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle, ): ListenableFuture<SessionResult> { val mediaItemId = args.getString(MediaConstants.EXTRA_KEY_MEDIA_ID) return if (mediaItemId != null) handleCustomCommandForMediaItem(controller, customCommand, mediaItemId, args) else handleCustomCommand(controller, customCommand, args) }
Java
@Override public ListenableFuture<SessionResult> onCustomCommand( MediaSession session, ControllerInfo controller, SessionCommand customCommand, Bundle args) { String mediaItemId = args.getString(MediaConstants.EXTRA_KEY_MEDIA_ID); return mediaItemId != null ? handleCustomCommandForMediaItem(controller, customCommand, mediaItemId, args) : handleCustomCommand(controller, customCommand, args); }
Menggunakan tombol perintah sebagai browser atau pengontrol
Di sisi MediaController, aplikasi dapat mendeklarasikan jumlah maksimum tombol
perintah yang didukungnya untuk item media saat mem-build MediaController atau
MediaBrowser:
Kotlin
val browserFuture = MediaBrowser.Builder(context, sessionToken).setMaxCommandsForMediaItems(3).buildAsync()
Java
ListenableFuture<MediaBrowser> browserFuture = new MediaBrowser.Builder(context, sessionToken).setMaxCommandsForMediaItems(3).buildAsync();
Saat terhubung ke sesi, aplikasi pengontrol dapat menerima tombol perintah yang didukung oleh item media dan yang perintahnya tersedia dan diberikan oleh aplikasi sesi untuk pengontrol:
Kotlin
val commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem)
Java
ImmutableList<CommandButton> commandButtonsForMediaItem = controller.getCommandButtonsForMediaItem(mediaItem);
Kotlin
val future = controller.sendCustomCommand( requireNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY, )
Java
ListenableFuture<SessionResult> future = controller.sendCustomCommand( checkNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY);