แสดงเนื้อหาด้วย MediaLibraryService

แอปสื่อมักมีคอลเล็กชันของรายการสื่อที่จัดระเบียบเป็นลำดับชั้น เช่น เพลงในอัลบั้มหรือตอนของรายการทีวีในเพลย์ลิสต์ ลำดับชั้นของ รายการสื่อนี้เรียกว่าคลังสื่อ

ตัวอย่างเนื้อหาสื่อที่จัดเรียงตามลำดับชั้น
รูปที่ 1: ตัวอย่างลำดับชั้นของรายการสื่อที่สร้างคลังสื่อ

MediaLibraryService มี API ที่ได้มาตรฐานเพื่อแสดงและเข้าถึงคลังสื่อ ซึ่งจะเป็นประโยชน์ เช่น เมื่อเพิ่มการรองรับ Android Auto ลงในแอปสื่อของคุณ ซึ่งมี UI ที่ปลอดภัยสำหรับผู้ขับขี่ของตัวเองสำหรับคลังสื่อ

สร้าง MediaLibraryService

การติดตั้งใช้งาน MediaLibraryService จะคล้ายกับ การติดตั้งใช้งาน MediaSessionService ยกเว้นว่าในเมธอด onGetSession() คุณควร ส่งคืน MediaLibrarySession แทน MediaSession

Kotlin

class PlaybackService : MediaLibraryService() {
  var mediaLibrarySession: MediaLibrarySession? = null
  var callback: MediaLibrarySession.Callback = object : MediaLibrarySession.Callback {...}

  // If desired, validate the controller before returning the media library session
  override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaLibrarySession? =
    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 และสิทธิ์ที่จำเป็นในไฟล์ Manifest ด้วย

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaSessionService"/>
        <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" />

ใช้ MediaLibrarySession

MediaLibraryService API คาดหวังให้คลังสื่อของคุณมีโครงสร้างในรูปแบบ ทรี โดยมีโหนดรูทเดียวและโหนดลูกที่อาจเล่นได้ หรือเรียกดูเพิ่มเติมได้

MediaLibrarySession ขยาย MediaSession API เพื่อเพิ่ม API การเรียกดูเนื้อหา เมื่อเทียบกับMediaSession Callback MediaLibrarySession Callback จะเพิ่มเมธอดต่างๆ เช่น

  • onGetLibraryRoot() เมื่อไคลเอ็นต์ขอรูทMediaItemของโครงสร้างเนื้อหา
  • onGetChildren() เมื่อไคลเอ็นต์ขอรายการย่อยของ MediaItem ในโครงสร้างเนื้อหา
  • onGetSearchResult() เมื่อไคลเอ็นต์ขอผลการค้นหาจากแผนผังเนื้อหาสำหรับคำค้นหาที่กำหนด

เมธอดเรียกกลับที่เกี่ยวข้องจะมีออบเจ็กต์ LibraryParams พร้อมสัญญาณเพิ่มเติมเกี่ยวกับประเภทของแผนผังเนื้อหาที่แอปไคลเอ็นต์ สนใจ

ปุ่มคำสั่งสำหรับรายการสื่อ

แอปเซสชันสามารถประกาศปุ่มคำสั่งที่ MediaItem รองรับใน MediaMetadata ได้ ซึ่งจะช่วยให้กำหนดCommandButtonรายการ อย่างน้อย 1 รายการให้กับรายการสื่อที่ตัวควบคุมแสดงและใช้เพื่อส่งคำสั่งที่กำหนดเอง สำหรับรายการไปยังเซสชันได้อย่างสะดวก

ตั้งค่าปุ่มคำสั่งในฝั่งเซสชัน

เมื่อสร้างเซสชัน แอปเซสชันจะประกาศชุดปุ่มคำสั่ง ที่เซสชันสามารถจัดการเป็นคำสั่งที่กำหนดเองได้ ดังนี้

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(),
    // possibly more here
  )

// 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();

เมื่อสร้างรายการสื่อ แอปเซสชันจะเพิ่มชุดรหัสคำสั่งที่รองรับได้ ซึ่งอ้างอิงถึงคำสั่งเซสชันของปุ่มคำสั่งที่ตั้งค่าไว้เมื่อ สร้างเซสชัน

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

เมื่อตัวควบคุมหรือเบราว์เซอร์เชื่อมต่อหรือเรียกใช้เมธอดอื่นของเซสชัน Callback แอปเซสชันจะตรวจสอบ ControllerInfo ที่ส่งไปยัง การเรียกกลับเพื่อรับจำนวนปุ่มคำสั่งสูงสุดที่ตัวควบคุมหรือเบราว์เซอร์ แสดงได้ ControllerInfo ที่ส่งผ่านไปยังเมธอด Callback จะมี Getter เพื่อเข้าถึงค่านี้ได้อย่างสะดวก โดยค่าเริ่มต้น ระบบจะตั้งค่าเป็น 0 ซึ่ง บ่งชี้ว่าเบราว์เซอร์หรือตัวควบคุมไม่รองรับฟีเจอร์นี้

Kotlin

override fun onGetItem(
  session: MediaLibrarySession,
  browser: MediaSession.ControllerInfo,
  mediaId: String,
): ListenableFuture<LibraryResult<MediaItem>> {

  val settableFuture = SettableFuture.create<LibraryResult<MediaItem>>()

  val maxCommandsForMediaItems = browser.maxCommandsForMediaItems
  scope.launch {
    loadMediaItem(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;
}

เมื่อจัดการการดำเนินการที่กำหนดเองซึ่งส่งมาสำหรับรายการสื่อ เซสชัน แอปจะรับรหัสรายการสื่อจากอาร์กิวเมนต์ Bundle ที่ส่งไปยัง 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);
}

ใช้ปุ่มคำสั่งเป็นเบราว์เซอร์หรือตัวควบคุม

ในฝั่ง MediaController แอปสามารถประกาศจำนวนปุ่มคำสั่งสูงสุดที่รองรับสำหรับรายการสื่อเมื่อสร้าง MediaController หรือ MediaBrowser ได้ดังนี้

Kotlin

val browserFuture =
  MediaBrowser.Builder(context, sessionToken)
    .setMaxCommandsForMediaItems(3)
    .buildAsync()

Java

ListenableFuture<MediaBrowser> browserFuture =
    new MediaBrowser.Builder(context, sessionToken)
        .setMaxCommandsForMediaItems(3)
        .buildAsync();

เมื่อเชื่อมต่อกับเซสชันแล้ว แอปตัวควบคุมจะรับ ปุ่มคำสั่งที่รายการสื่อรองรับและ ตัวควบคุมมีคำสั่งที่พร้อมใช้งานซึ่งแอปเซสชันให้สิทธิ์ได้

Kotlin

val commandButtonsForMediaItem: List<CommandButton> =
  controller.getCommandButtonsForMediaItem(mediaItem)

Java

ImmutableList<CommandButton> commandButtonsForMediaItem =
    controller.getCommandButtonsForMediaItem(mediaItem);

เพื่อความสะดวก MediaController สามารถส่งคำสั่งที่กำหนดเองสำหรับรายการสื่อที่เฉพาะเจาะจง ด้วย MediaController.sendCustomCommand(SessionCommand, MediaItem, Bundle) ได้

Kotlin

controller.sendCustomCommand(addToPlaylistButton.sessionCommand!!, mediaItem, Bundle.EMPTY)

Java

controller.sendCustomCommand(
    checkNotNull(addToPlaylistButton.sessionCommand), mediaItem, Bundle.EMPTY);