Nghe các sự kiện phát
Các sự kiện, chẳng hạn như thay đổi về trạng thái và lỗi phát, được báo cáo cho các thực thể Player.Listener đã đăng ký. Cách đăng ký một trình nghe để nhận các sự kiện như vậy:
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 có các phương thức mặc định trống, vì vậy, bạn chỉ cần triển khai các phương thức mà bạn quan tâm. Hãy xem Javadoc để biết nội dung mô tả đầy đủ về các phương thức và thời điểm chúng được gọi. Một số phương thức quan trọng nhất được mô tả chi tiết hơn bên dưới.
Người nghe có thể chọn triển khai các lệnh gọi lại sự kiện riêng lẻ hoặc lệnh gọi lại onEvents chung được gọi sau khi một hoặc nhiều sự kiện xảy ra cùng nhau. Hãy xem phần Individual callbacks vs onEvents để biết giải thích về lựa chọn ưu tiên cho các trường hợp sử dụng khác nhau.
Các thay đổi về trạng thái phát
Bạn có thể nhận được các thay đổi về trạng thái trình phát bằng cách triển khai onPlaybackStateChanged(@State int state) trong một Player.Listener đã đăng ký.
Trình phát có thể ở một trong bốn trạng thái phát sau:
Player.STATE_IDLE: Đây là trạng thái ban đầu, trạng thái khi trình phát dừng và khi quá trình phát không thành công. Trình phát sẽ chỉ giữ một số ít tài nguyên ở trạng thái này.Player.STATE_BUFFERING: Trình phát không thể phát ngay từ vị trí hiện tại. Điều này thường xảy ra vì cần tải thêm dữ liệu.Player.STATE_READY: Trình phát có thể phát ngay từ vị trí hiện tại.Player.STATE_ENDED: Trình phát đã phát xong tất cả nội dung nghe nhìn.
Ngoài các trạng thái này, trình phát còn có cờ playWhenReady để cho biết ý định phát của người dùng. Bạn có thể nhận được các thay đổi trong cờ này bằng cách triển khai onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason).
Trình phát đang phát (tức là vị trí của trình phát đang tiến và nội dung nghe nhìn đang được trình bày cho người dùng) khi đáp ứng cả 3 điều kiện sau:
- Trình phát đang ở trạng thái
Player.STATE_READY playWhenReadylàtrue- Quá trình phát không bị chặn vì một lý do do
Player.getPlaybackSuppressionReasontrả về
Thay vì phải kiểm tra từng thuộc tính này, bạn có thể gọi Player.isPlaying. Bạn có thể nhận các thay đổi đối với trạng thái này bằng cách triển khai 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. } } });
Lỗi phát lại
Bạn có thể nhận được các lỗi khiến quá trình phát không thành công bằng cách triển khai onPlayerError(PlaybackException error) trong Player.Listener đã đăng ký. Khi xảy ra lỗi, phương thức này sẽ được gọi ngay trước khi trạng thái phát chuyển sang Player.STATE_IDLE. Bạn có thể thử lại các lần phát không thành công hoặc bị dừng bằng cách gọi ExoPlayer.prepare.
Xin lưu ý rằng một số cách triển khai Player sẽ truyền các thực thể của lớp con PlaybackException để cung cấp thêm thông tin về lỗi. Ví dụ: ExoPlayer truyền ExoPlaybackException, có type, rendererIndex và các trường khác dành riêng cho ExoPlayer.
Ví dụ sau đây minh hoạ cách phát hiện thời điểm quá trình phát không thành công do sự cố mạng 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. } } } });
Hiệu ứng chuyển cảnh trong danh sách phát
Bất cứ khi nào trình phát chuyển sang một mục nội dung nghe nhìn mới trong Danh sách phát, onMediaItemTransition(MediaItem mediaItem, @MediaItemTransitionReason int
reason) sẽ được gọi trên các đối tượng Player.Listener đã đăng ký. Lý do cho biết đây có phải là một quá trình chuyển đổi tự động, một thao tác tìm kiếm (ví dụ: sau khi gọi player.next()), một thao tác lặp lại cùng một mục hay do thay đổi danh sách phát (ví dụ: nếu mục đang phát bị xoá).
Metadata
Siêu dữ liệu được trả về từ player.getCurrentMediaMetadata() có thể thay đổi vì nhiều lý do: chuyển đổi danh sách phát, cập nhật siêu dữ liệu trong luồng phát hoặc cập nhật MediaItem hiện tại trong quá trình phát.
Nếu quan tâm đến các thay đổi về siêu dữ liệu (ví dụ: để cập nhật giao diện người dùng hiển thị tiêu đề hiện tại), bạn có thể theo dõi onMediaMetadataChanged.
Đang tìm kiếm
Việc gọi các phương thức Player.seekTo sẽ dẫn đến một loạt lệnh gọi lại cho các thực thể Player.Listener đã đăng ký:
onPositionDiscontinuityvớireason=DISCONTINUITY_REASON_SEEK. Đây là kết quả trực tiếp của việc gọiPlayer.seekTo. Lệnh gọi lại có các trườngPositionInfocho vị trí trước và sau thao tác tìm kiếm.onPlaybackStateChangedvới mọi thay đổi về trạng thái ngay lập tức liên quan đến thao tác tìm kiếm. Xin lưu ý rằng có thể không có thay đổi nào như vậy.
Lệnh gọi lại riêng lẻ so với onEvents
Trình nghe có thể chọn giữa việc triển khai các lệnh gọi lại riêng lẻ như onIsPlayingChanged(boolean isPlaying) và lệnh gọi lại chung onEvents(Player
player, Events events). Lệnh gọi lại chung cung cấp quyền truy cập vào đối tượng Player và chỉ định tập hợp events đã xảy ra cùng nhau. Lệnh gọi lại này luôn được gọi sau các lệnh gọi lại tương ứng với từng sự kiện.
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); } }
Bạn nên sử dụng các sự kiện riêng lẻ trong những trường hợp sau:
- Người nghe quan tâm đến lý do của những thay đổi. Ví dụ: lý do được cung cấp cho
onPlayWhenReadyChangedhoặconMediaItemTransition. - Trình nghe chỉ hoạt động trên các giá trị mới được cung cấp thông qua các tham số gọi lại hoặc kích hoạt một số hoạt động khác không phụ thuộc vào các tham số gọi lại.
- Việc triển khai trình nghe ưu tiên một chỉ báo rõ ràng, dễ đọc về điều gì đã kích hoạt sự kiện trong tên phương thức.
- Trình nghe báo cáo cho một hệ thống phân tích cần biết về tất cả các sự kiện riêng lẻ và thay đổi trạng thái.
Bạn nên ưu tiên sử dụng onEvents(Player player, Events events) chung trong các trường hợp sau:
- Trình nghe muốn kích hoạt cùng một logic cho nhiều sự kiện. Ví dụ: cập nhật giao diện người dùng cho cả
onPlaybackStateChangedvàonPlayWhenReadyChanged. - Trình nghe cần truy cập vào đối tượng
Playerđể kích hoạt các sự kiện khác, chẳng hạn như tìm kiếm sau khi chuyển đổi mục nội dung nghe nhìn. - Trình nghe dự định sử dụng nhiều giá trị trạng thái được báo cáo cùng nhau thông qua các lệnh gọi lại riêng biệt hoặc kết hợp với các phương thức getter
Player. Ví dụ: việc sử dụngPlayer.getCurrentWindowIndex()vớiTimelineđược cung cấp trongonTimelineChangedchỉ an toàn trong lệnh gọi lạionEvents. - Trình nghe quan tâm đến việc các sự kiện có xảy ra cùng nhau một cách hợp lý hay không.
Ví dụ:
onPlaybackStateChangedthànhSTATE_BUFFERINGdo quá trình chuyển đổi mục nội dung nghe nhìn.
Trong một số trường hợp, người nghe có thể cần kết hợp các lệnh gọi lại riêng lẻ với lệnh gọi lại onEvents chung, chẳng hạn như ghi lại lý do thay đổi mục nội dung nghe nhìn bằng onMediaItemTransition, nhưng chỉ hành động khi tất cả các thay đổi về trạng thái có thể được dùng cùng nhau trong onEvents.
Sử dụng AnalyticsListener
Khi sử dụng ExoPlayer, bạn có thể đăng ký AnalyticsListener với trình phát bằng cách gọi addAnalyticsListener. Các hoạt động triển khai AnalyticsListener có thể theo dõi các sự kiện chi tiết có thể hữu ích cho mục đích phân tích và ghi nhật ký. Vui lòng tham khảo trang số liệu phân tích để biết thêm thông tin chi tiết.
Sử dụng EventLogger
EventLogger là một AnalyticsListener do thư viện cung cấp trực tiếp cho mục đích ghi nhật ký. Thêm EventLogger vào ExoPlayer để bật tính năng ghi nhật ký bổ sung hữu ích chỉ bằng một dòng:
Kotlin
player.addAnalyticsListener(EventLogger())
Java
player.addAnalyticsListener(new EventLogger());
Hãy xem trang ghi nhật ký gỡ lỗi để biết thêm thông tin chi tiết.
Kích hoạt sự kiện tại các vị trí phát được chỉ định
Một số trường hợp sử dụng yêu cầu kích hoạt các sự kiện tại những vị trí phát cụ thể. Điều này được hỗ trợ bằng PlayerMessage. Bạn có thể tạo PlayerMessage bằng cách sử dụng ExoPlayer.createMessage. Bạn có thể đặt vị trí phát mà tại đó thao tác này sẽ được thực thi bằng cách sử dụng PlayerMessage.setPosition. Theo mặc định, các thông báo được thực thi trên luồng phát, nhưng bạn có thể tuỳ chỉnh thông báo này bằng cách sử dụng PlayerMessage.setLooper. Bạn có thể dùng PlayerMessage.setDeleteAfterDelivery để kiểm soát việc thông báo sẽ được thực thi mỗi khi gặp vị trí phát được chỉ định (điều này có thể xảy ra nhiều lần do chế độ tìm kiếm và lặp lại) hay chỉ lần đầu tiên. Sau khi bạn định cấu hình PlayerMessage, bạn có thể lên lịch cho PlayerMessage bằng cách sử dụng 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();