Sự kiện của người chơi

Nghe sự kiện phát

Các sự kiện, chẳng hạn như các thay đổi về trạng thái và lỗi phát, được báo cáo cho những người đã đăng ký Player.Listener thực thể. Để đăng ký một trình nghe nhận sự kiện:

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 nên bạn chỉ cần triển khai các phương pháp mà mình quan tâm. Vui lòng 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 pháp quan trọng nhất là được mô tả chi tiết hơn bên dưới.

Trình nghe có thể lựa chọn giữa việc triển khai các lệnh gọi lại sự kiện riêng lẻ hoặc một 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 khi kết hợp cùng nhau. Xem Individual callbacks vs onEvents để biết nội dung giải thích về cần được ư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

Có thể nhận được các thay đổi về trạng thái của người chơi bằng cách triển khai onPlaybackStateChanged(@State int state) trong một đăng ký Player.Listener Trình phát có thể ở một trong bốn trạng thái phát:

  • Player.STATE_IDLE: Đây là trạng thái ban đầu khi người chơi đã dừng và khi phát không thành công. Người chơi sẽ chỉ có tài nguyên giới hạn ở trạng thái này.
  • Player.STATE_BUFFERING: Người chơi không thể chơi ngay trên vị trí hiện tại. Điều này chủ yếu xảy ra vì cần tải nhiều dữ liệu hơn.
  • Player.STATE_READY: Người chơi có thể chơi ngay từ trò chơi hiện tại vị trí.
  • 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, người chơi còn có một cờ playWhenReady để cho biết ý định chơi của người dùng. Bạn có thể nhận được các thay đổi về cờ này bằng cách triển khai onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason).

Người chơi đang chơi (tức là vị trí của người chơi đang thăng cấp còn nội dung nghe nhìn đang chuyển động cho người dùng) khi đáp ứng cả ba điều kiện sau:

  • Người chơi đang ở trạng thái Player.STATE_READY
  • playWhenReadytrue
  • Phát không bị chặn vì lý do mà Player.getPlaybackSuppressionReason

Thay vì phải kiểm tra từng thuộc tính, Player.isPlaying . Có thể nhận được 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

Có thể nhận được các lỗi khiến phát lại không thành công bằng cách triển khai onPlayerError(PlaybackException error) trong một đăng ký Player.Listener 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 hoặc dừng phát bằng cách gọi ExoPlayer.prepare.

Lưu ý rằng một số phương thức triển khai Player truyền các thực thể của lớp con của PlaybackException để cung cấp thêm thông tin về lỗi. Cho 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 trình bày cách phát hiện khi một lượt phát không thành công do Vấn đề kết nối 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.
          }
        }
      }
    });

Chuyển đổi danh sách phát

Bất cứ khi nào trình phát thay đổi 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) được gọi trên các thiết bị đã đăng ký Đối tượng Player.Listener. Lý do cho biết liệu đây có phải là truy vấn tự động chuyển đổi, tua (ví dụ: sau khi gọi player.next()), lặp lại cùng một mục hoặc do thay đổi về danh sách phát gây ra (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 do có nhiều lý do: chuyển đổi danh sách phát, cập nhật siêu dữ liệu trong luồng hoặc cập nhật video đang phát giữa video MediaItem.

Nếu bạn quan tâm đến việc thay đổi siêu dữ liệu, chẳng hạn như để cập nhật giao diện người dùng cho thấy tên hiện tại, bạn có thể nghe onMediaMetadataChanged.

Đang tìm kiếm

Việc gọi phương thức Player.seekTo sẽ dẫn đến một loạt lệnh gọi lại đến các phương thức đã đăng ký Player.Listener thực thể:

  1. onPositionDiscontinuity cho thành viên reason=DISCONTINUITY_REASON_SEEK. Đây là kết quả trực tiếp của việc gọi Player.seekTo. Lệnh gọi lại có PositionInfo các trường cho vị trí trước và sau khi tìm kiếm.
  2. onPlaybackStateChanged với mọi thay đổi về trạng thái tức thì liên quan đến lượt tìm kiếm. Xin lưu ý rằng có thể sẽ không có thay đổi nào như vậy.

Các 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 từng lệnh gọi lại riêng lẻ như onIsPlayingChanged(boolean isPlaying) và thuộc tính chung Lệnh gọi lại 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 khi kết hợp 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 ưu tiên các sự kiện riêng lẻ trong các trường hợp sau:

  • Người nghe quan tâm đến lý do thay đổi. Ví dụ: lý do được đưa ra cho onPlayWhenReadyChanged hoặc onMediaItemTransition.
  • Trình nghe chỉ hành độ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 yếu tố khác không phụ thuộc vào các tham số của lệnh gọi lại.
  • Quá trình triển khai trình nghe ưu tiên chỉ báo dễ đọc về những gì đã kích hoạt sự kiện trong tên phương thức.
  • Trình nghe báo cáo cho 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 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. Cho ví dụ: cập nhật giao diện người dùng cho cả onPlaybackStateChangedonPlayWhenReadyChanged
  • Trình nghe cần truy cập vào đối tượng Player để kích hoạt thêm các sự kiện, ví dụ: tìm kiếm sau khi chuyển đổi một mục nội dung đa phương tiện.
  • Trình nghe dự định sử dụng nhiều giá trị trạng thái được báo cáo thông qua các lệnh gọi lại riêng biệt hoặc kết hợp với phương thức getter Player . Ví dụ: sử dụng Player.getCurrentWindowIndex() với thuộc tính Timeline được cung cấp trong onTimelineChanged chỉ an toàn từ bên trong Gọi lại onEvents.
  • Trình nghe muốn biết liệu các sự kiện có xảy ra cùng nhau theo logic hay không. Cho ví dụ: onPlaybackStateChanged thành STATE_BUFFERING do một mục nội dung đa phương tiện chuyển đổi.

Trong một số trường hợp, trình 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, ví dụ để ghi lại lý do thay đổi mục nội dung đa phương tiện bằng onMediaItemTransition, nhưng chỉ hành động khi có thể sử dụng tất cả thay đổi về trạng thái cùng nhau trong onEvents.

Sử dụng AnalyticsListener

Khi sử dụng ExoPlayer, người chơi có thể đăng ký AnalyticsListener bằng cách gọi addAnalyticsListener. Có thể triển khai AnalyticsListener để nghe các sự kiện chi tiết có thể hữu ích cho việc 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 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 để kích hoạt thông tin hữu ích ghi nhật ký bổ sung chỉ một dòng duy nhất:

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.

Sự kiện kích hoạt tại những vị trí phát đã chỉ định

Một số trường hợp sử dụng yêu cầu phải kích hoạt sự kiện tại những vị trí phát cụ thể. Đây là được hỗ trợ bằng PlayerMessage. Bạn có thể tạo PlayerMessage bằng ExoPlayer.createMessage Vị trí phát mà đoạn mã sẽ được thực thi có thể đặt bằng PlayerMessage.setPosition. Thông báo được thực thi trên theo mặc định, nhưng bạn có thể tuỳ chỉnh luồng này bằng cách sử dụng PlayerMessage.setLooper. Có thể sử dụng PlayerMessage.setDeleteAfterDelivery để kiểm soát liệu thông báo có được thực thi mỗi lần lệnh được chỉ định hay không gặp phải vị trí phát (điều này có thể xảy ra nhiều lần do tua và chế độ lặp lại) hoặc chỉ lần đầu tiên. Sau khi PlayerMessage được đã định cấu hình, bạn có thể lên lịch sự kiện này bằ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();