監聽播放事件
事件 (例如狀態變更和播放錯誤) 會回報為已註冊的事件
Player.Listener
執行個體。如要註冊接聽程式來接收這類
事件:
Kotlin
// Add a listener to receive events from the player. player.addListener(listener)
Java
// Add a listener to receive events from the player. player.addListener(listener);
Player.Listener
含有空白的預設方法,因此您只需要實作
要查看的方法如需完整的
方法和呼叫的時機以下列舉幾個最重要的方法
。
事件監聽器可以選擇實作個別事件回呼,也可以使用的是
系統在一或多個事件發生後呼叫的一般 onEvents
回呼
。詳情請參閱 Individual callbacks vs onEvents
。
建議分別用於不同用途
播放狀態變更
可透過實作
已完成註冊的 onPlaybackStateChanged(@State int state)
Player.Listener
。播放器可能處於以下四種播放狀態之一:
Player.STATE_IDLE
:這是初始狀態,也就是玩家 以及播放失敗時玩家只能擁有有限資源 執行同樣的動作Player.STATE_BUFFERING
:播放器無法立即從其位置播放 目前位置。這通常是因為需要載入更多資料。Player.STATE_READY
:玩家可以立即從目前的遊戲開始播放 位置。Player.STATE_ENDED
:播放器已播放所有媒體。
除了這些狀態之外,播放器還會有 playWhenReady
旗標來表示
使用者的遊戲意圖。可透過實作
onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason)
。
播放器正在播放 (即播放器的位置正在推進,而媒體會隨著播放) 顯示的使用者)。
- 播放器處於
Player.STATE_READY
狀態 - 「
playWhenReady
」將在true
後開始 - 播放失敗,原因是
Player.getPlaybackSuppressionReason
因此您不必個別查看這些屬性 Player.isPlaying
可以呼叫這些函式可透過實作
onIsPlayingChanged(boolean isPlaying)
:
Kotlin
player.addListener( object : Player.Listener { override fun onIsPlayingChanged(isPlaying: Boolean) { if (isPlaying) { // Active playback. } else { // Not playing because playback is paused, ended, suppressed, or the player // is buffering, stopped or failed. Check player.playWhenReady, // player.playbackState, player.playbackSuppressionReason and // player.playerError for details. } } } )
Java
player.addListener( new Player.Listener() { @Override public void onIsPlayingChanged(boolean isPlaying) { if (isPlaying) { // Active playback. } else { // Not playing because playback is paused, ended, suppressed, or the player // is buffering, stopped or failed. Check player.getPlayWhenReady, // player.getPlaybackState, player.getPlaybackSuppressionReason and // player.getPlaybackError for details. } } });
播放錯誤
實作可接收播放失敗的錯誤
已完成註冊的 onPlayerError(PlaybackException error)
Player.Listener
。如果作業失敗,系統會呼叫此方法
播放狀態轉變成 Player.STATE_IDLE
之前。
您可以呼叫 ExoPlayer.prepare
來重試播放失敗或停止播放的情況。
請注意,部分 Player
實作會傳遞
PlaybackException
,提供失敗原因的額外資訊。適用對象
例如,ExoPlayer
傳遞 ExoPlaybackException
,其中包含 type
。
rendererIndex
和其他 ExoPlayer 專用欄位。
以下範例說明如何偵測影片是否因 HTTP 網路問題:
Kotlin
player.addListener( object : Player.Listener { override fun onPlayerError(error: PlaybackException) { val cause = error.cause if (cause is HttpDataSourceException) { // An HTTP error occurred. val httpError = cause // It's possible to find out more about the error both by casting and by querying // the cause. if (httpError is InvalidResponseCodeException) { // Cast to InvalidResponseCodeException and retrieve the response code, message // and headers. } else { // Try calling httpError.getCause() to retrieve the underlying cause, although // note that it may be null. } } } } )
Java
player.addListener( new Player.Listener() { @Override public void onPlayerError(PlaybackException error) { @Nullable Throwable cause = error.getCause(); if (cause instanceof HttpDataSourceException) { // An HTTP error occurred. HttpDataSourceException httpError = (HttpDataSourceException) cause; // It's possible to find out more about the error both by casting and by querying // the cause. if (httpError instanceof HttpDataSource.InvalidResponseCodeException) { // Cast to InvalidResponseCodeException and retrieve the response code, message // and headers. } else { // Try calling httpError.getCause() to retrieve the underlying cause, although // note that it may be null. } } } });
播放清單轉場效果
每當播放器變更播放清單中的新媒體項目時
onMediaItemTransition(MediaItem mediaItem,
@MediaItemTransitionReason int reason)
已在登錄上呼叫
Player.Listener
物件。原因會指出是否為自動
轉場效果、跳轉 (例如在呼叫 player.next()
後),重複
或是由播放清單變更造成的 (例如,如果目前
播放項目時)。
中繼資料
由於許多原因,從 player.getCurrentMediaMetadata()
傳回的中繼資料可能有所變動
造成播放清單轉換、串流內中繼資料更新或更新
目前的 MediaItem
在播放中。
對中繼資料的異動 例如更新
目前可以播放onMediaMetadataChanged
。
正在指定播放時間點
呼叫 Player.seekTo
方法會導致一系列回呼已註冊
Player.Listener
執行個體:
reason=DISCONTINUITY_REASON_SEEK
會員價onPositionDiscontinuity
。這是 呼叫Player.seekTo
的直接結果。回呼有PositionInfo
] 欄位來代表跳轉前後的位置。onPlaybackStateChanged
,且與跳轉相關的任何立即狀態變更。 請注意,這類變更不一定會發生。
個別回呼與 onEvents
事件監聽器可以選擇實作個別回呼,例如
onIsPlayingChanged(boolean isPlaying)
和一般
onEvents(Player player, Events events)
回呼。一般回呼會提供
存取 Player
物件,並指定發生的 events
組合
。系統一律會在對應的回呼函式後呼叫此回呼
個別事件
Kotlin
override fun onEvents(player: Player, events: Player.Events) { if ( events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED) ) { uiModule.updateUi(player) } }
Java
@Override public void onEvents(Player player, Events events) { if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) { uiModule.updateUi(player); } }
建議在下列情況下優先使用個別事件:
- 事件監聽器想瞭解變更的原因。舉例來說,
原因為
onPlayWhenReadyChanged
或onMediaItemTransition
。 - 事件監聽器只會對透過回呼參數提供的新值採取行動 也可以觸發不依賴回呼參數的其他內容。
- 事件監聽器實作偏好清楚易讀的 觸發了方法名稱中的事件。
- 事件監聽器向分析系統回報,該系統中需瞭解 個別事件和狀態變更
一般的 onEvents(Player player, Events events)
應優先採用
下列情況:
- 事件監聽器想為多個事件觸發相同邏輯。適用對象
例如,更新
onPlaybackStateChanged
和onPlayWhenReadyChanged
。 - 事件監聽器需要存取
Player
物件,才能觸發後續事件。 例如在媒體項目轉換後跳轉 - 事件監聽器想要使用回報的多個狀態值
搭配使用個別回呼,或與
Player
getter 搭配使用 方法。例如,使用Player.getCurrentWindowIndex()
搭配onTimelineChanged
中提供的Timeline
只能在onEvents
回呼。 - 事件監聽器想瞭解事件是否有邏輯發生。適用對象
例如
onPlaybackStateChanged
到STATE_BUFFERING
,因為某個媒體項目 轉換。
在某些情況下,事件監聽器可能需要將個別回呼與
一般 onEvents
回呼,例如記錄媒體項目變更原因
具備 onMediaItemTransition
,但只能在可使用所有狀態變更時執行
透過 onEvents
整合。
使用AnalyticsListener
使用 ExoPlayer
時,可以向玩家註冊 AnalyticsListener
呼叫 addAnalyticsListener
。AnalyticsListener
項導入後可
監聽適合用於數據分析和記錄的詳細事件
用途。詳情請參閱數據分析頁面。
使用EventLogger
EventLogger
是由以下程式庫直接提供的 AnalyticsListener
:
以便進行記錄。在 ExoPlayer
中新增 EventLogger
,以啟用實用的功能
即可:
Kotlin
player.addAnalyticsListener(EventLogger())
Java
player.addAnalyticsListener(new EventLogger());
詳情請參閱偵錯記錄頁面。
在指定的播放位置觸發事件
部分用途需要在指定的播放位置觸發事件。這是
支援使用 PlayerMessage
。可以用 PlayerMessage
建立
ExoPlayer.createMessage
。應執行播放器的播放位置
您可使用 PlayerMessage.setPosition
進行設定。訊息會在
預設播放執行緒,但如要自訂播放方式,請使用
PlayerMessage.setLooper
。PlayerMessage.setDeleteAfterDelivery
可使用
控制訊息是否會在指定的每次指定時執行
發生播放位置時 (可能會因為跳轉而多次變更)
或重複模式) 或第一次設定。PlayerMessage
可以使用 PlayerMessage.send
排程
Kotlin
player .createMessage { messageType: Int, payload: Any? -> } .setLooper(Looper.getMainLooper()) .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120000) .setPayload(customPayloadData) .setDeleteAfterDelivery(false) .send()
Java
player .createMessage( (messageType, payload) -> { // Do something at the specified playback position. }) .setLooper(Looper.getMainLooper()) .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120_000) .setPayload(customPayloadData) .setDeleteAfterDelivery(false) .send();