播放器介面

播放器是應用程式中的元件,可協助播放媒體項目。Media3 Player 介面會為通常由播放器處理的功能設定大綱。包括:

  • 影響播放控制項,例如播放、暫停和跳轉
  • 查詢目前播放媒體的屬性,例如播放位置
  • 管理媒體項目的播放清單/佇列
  • 設定播放屬性,例如隨機播放、重複播放、速度和音量
  • 將影片轉譯至螢幕

Media3 也提供 Player 介面的實作項目,稱為 ExoPlayer

元件之間的通用介面

Media3 中的幾個元件會實作 Player 介面,例如:

元件 說明與行為附註
ExoPlayer 媒體播放器 API,以及 Player 介面的預設實作方式。
MediaController MediaSession 互動,以便傳送播放指令。如果 PlayerMediaSession 位於 Service 中,而 Service 與播放器 UI 所在的 ActivityFragment 不同,您可以將 MediaController 指派為 PlayerView UI 的播放器。播放和播放清單方法呼叫會透過 MediaSession 傳送至 Player
MediaBrowser 除了 MediaController 提供的功能外,還可與 MediaLibrarySession 互動,瀏覽可用的媒體內容。
SimpleBasePlayer Player 實作項目,可將要實作的函式數量降至最低。當您要使用要連線至 MediaSession 的自訂播放器時,這項屬性就很實用。
ForwardingSimpleBasePlayer SimpleBasePlayer 子類別,旨在將播放操作轉送至其他 Player,同時允許與 SimpleBasePlayer 相同的一致行為自訂設定。使用這個類別來抑制或修改特定播放作業。
CastPlayer 與 Cast 接收器應用程式通訊的 Player 實作項目。行為取決於基礎的 Cast 工作階段。

雖然 MediaSession 不會實作 Player 介面,但建立 MediaSession 時需要 Player。其目的是透過其他程序或執行緒提供對 Player 的存取權。

Media3 播放架構

如果您有權存取 Player,請直接呼叫其方法,以便發出播放指令。您可以實作 MediaSession,宣傳您的播放功能並授予外部來源播放控制權。這些外部來源會實作 MediaController,方便連線至媒體工作階段並發出播放指令請求。

在背景播放媒體時,您必須在以前景服務執行的 MediaSessionServiceMediaLibraryService 中安置媒體工作階段和播放器。這樣一來,您就能將播放器與應用程式中的活動分開,後者包含播放控制項的 UI。因此,您可能需要使用媒體控制器。

顯示 Media3 播放元件如何融入媒體應用程式架構的圖表。
圖 1Player 介面在 Media3 架構中扮演重要角色。

播放器狀態

實作 Player 介面的媒體播放器狀態主要包含 4 類資訊:

  1. 播放狀態
  2. 媒體項目播放清單
  3. 播放/暫停屬性,例如:
    • playWhenReady:指出使用者是否希望媒體在可播放時播放,或保持暫停狀態
    • 播放抑制原因:指出播放內容遭到抑制的原因 (如果適用),即使 playWhenReadytrue 也一樣
    • isPlaying:指出播放器目前是否正在播放,只有在播放狀態為 STATE_READYplayWhenReadytrue,且播放未遭到抑制時,才會是 true
  4. 播放位置,包括:

此外,Player 介面可讓您存取可用的音軌媒體中繼資料播放速度音量和其他播放輔助屬性。

監聽變更

使用 Player.Listener 監聽 Player 中的變更。如需建立及使用事件監聽器的詳細資訊,請參閱 ExoPlayer 說明文件中的「Player 事件」一節。

請注意,監聽器介面不包含任何回呼,無法追蹤正常的播放進度。如要持續監控播放進度 (例如設定進度列 UI),您應以適當的間隔查詢目前位置。

Kotlin

val handler = Handler(Looper.getMainLooper())
fun checkPlaybackPosition(delayMs: Long): Boolean =
  handler.postDelayed(
    {
      val currentPosition = player.currentPosition
      // Update UI based on currentPosition
      checkPlaybackPosition(delayMs)
    },
    delayMs)

Java

Handler handler = new Handler(Looper.getMainLooper());
boolean checkPlaybackPosition(long delayMs) {
    return handler.postDelayed(() -> {
        long currentPosition = player.getCurrentPosition();
        // Update UI based on currentPosition
        checkPlaybackPosition(delayMs);
    }, delayMs);
}

控制播放功能

Player 介面提供多種方法,可用於操控狀態及控制播放:

自訂 Player 實作

如要建立自訂播放器,您可以擴充 Media3 中的 SimpleBasePlayer。這個類別提供 Player 介面的基礎實作項目,可將您需要實作的函式數量降至最低。

首先,覆寫 getState() 方法。這個方法在呼叫時應填入目前的播放器狀態,包括:

  • 可用的指令集
  • 播放屬性,例如播放器應在播放狀態為 STATE_READY 時開始播放、目前播放的媒體項目索引,以及目前項目中的播放位置

Kotlin

class CustomPlayer : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build()
  }
}

Java

public class CustomPlayer extends SimpleBasePlayer {
  public CustomPlayer(Looper looper) {
    super(looper);
  }

  @Override
  protected State getState() {
    return new State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build();
  }
}

SimpleBasePlayer 會強制使用有效的狀態值組合建立 State。它也會處理監聽器,並通知監聽器狀態變更。如果需要手動觸發狀態更新,請呼叫 invalidateState()

除了 getState() 方法之外,您只需實作用於玩家宣告可用的命令的方法。找出對應於要實作功能的覆寫處理常式方法。舉例來說,您可以覆寫 handleSeek() 方法,以支援 COMMAND_SEEK_IN_CURRENT_MEDIA_ITEMCOMMAND_SEEK_TO_NEXT_MEDIA_ITEM 等作業。