การฟังเหตุการณ์การเล่น
ระบบจะรายงานเหตุการณ์ต่างๆ เช่น การเปลี่ยนแปลงสถานะและข้อผิดพลาดในการเล่น ไปยังอินสแตนซ์ที่ลงทะเบียน
Player.Listener หากต้องการลงทะเบียน 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 มีเมธอดเริ่มต้นที่ว่างเปล่า คุณจึงต้องใช้เฉพาะเมธอดที่คุณสนใจเท่านั้น ดูคำอธิบายแบบเต็มของเมธอดและเวลาที่เรียกใช้ได้ใน Javadoc
เราจะอธิบายวิธีการที่สำคัญที่สุดบางส่วนอย่างละเอียดด้านล่าง
ผู้ฟังสามารถเลือกระหว่างการใช้การเรียกกลับของเหตุการณ์แต่ละรายการหรือonEventsการเรียกกลับทั่วไปที่เรียกใช้หลังจากเกิดเหตุการณ์อย่างน้อย 1 รายการพร้อมกัน
ดูคำอธิบายว่าควรเลือกใช้Individual callbacks vs onEventsใดสำหรับกรณีการใช้งานต่างๆ
การเปลี่ยนแปลงสถานะการเล่น
คุณรับการเปลี่ยนแปลงสถานะเพลเยอร์ได้โดยการใช้ onPlaybackStateChanged(@State int state) ใน Player.Listener ที่ลงทะเบียน
โดยเพลเยอร์อาจอยู่ในสถานะการเล่น 1 ใน 4 สถานะต่อไปนี้
Player.STATE_IDLE: นี่คือสถานะเริ่มต้น สถานะเมื่อเพลเยอร์หยุดเล่น และเมื่อการเล่นล้มเหลว โดยเพลเยอร์จะเก็บเฉพาะ ทรัพยากรที่จำกัดในสถานะนี้Player.STATE_BUFFERING: เพลเยอร์ไม่สามารถเล่นจากตำแหน่งปัจจุบันได้ทันที ปัญหานี้มักเกิดขึ้นเนื่องจากต้องโหลดข้อมูลเพิ่มเติมPlayer.STATE_READY: ผู้เล่นสามารถเล่นต่อจากตำแหน่งปัจจุบันได้ทันทีPlayer.STATE_ENDED: โปรแกรมเล่นเล่นสื่อทั้งหมดเสร็จแล้ว
นอกจากสถานะเหล่านี้แล้ว ผู้เล่นยังมีplayWhenReadyแฟล็กเพื่อระบุ
ความตั้งใจของผู้ใช้ที่จะเล่นด้วย คุณรับการเปลี่ยนแปลงในฟีเจอร์นี้ได้โดยการติดตั้งใช้งาน
onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason)
เพลเยอร์กำลังเล่น (กล่าวคือ ตำแหน่งของเพลเยอร์กำลังเลื่อนไปข้างหน้าและระบบกำลังแสดงสื่อต่อผู้ใช้) เมื่อตรงตามเงื่อนไขทั้ง 3 ข้อต่อไปนี้
- ผู้เล่นอยู่ในสถานะ
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 ปัจจุบันขณะเล่น
หากสนใจการเปลี่ยนแปลงข้อมูลเมตา เช่น การอัปเดต UI ที่แสดงชื่อปัจจุบัน คุณสามารถฟัง onMediaMetadataChanged ได้
กำลังค้นหา
การเรียกใช้เมธอด Player.seekTo จะทำให้เกิดชุดของ Callback ไปยังอินสแตนซ์ Player.Listener ที่ลงทะเบียนไว้
onPositionDiscontinuityด้วยreason=DISCONTINUITY_REASON_SEEKซึ่งเป็นผลโดยตรงจากการเรียกใช้Player.seekToโดย Callback มีฟิลด์PositionInfoสำหรับตำแหน่งก่อนและหลังการกรอonPlaybackStateChangedที่มีการเปลี่ยนแปลงสถานะทันทีที่เกี่ยวข้องกับ seek โปรดทราบว่าอาจไม่มีการเปลี่ยนแปลงดังกล่าว
การโทรกลับแบบรายบุคคลเทียบกับ onEvents
ผู้ฟังสามารถเลือกระหว่างการใช้การเรียกกลับแต่ละรายการ เช่น
onIsPlayingChanged(boolean isPlaying) และการเรียกกลับ onEvents(Player
player, Events events) ทั่วไป Callback ทั่วไปช่วยให้เข้าถึงออบเจ็กต์ 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 - โดย Listener จะดำเนินการกับค่าใหม่ที่ระบุผ่านพารามิเตอร์การเรียกกลับเท่านั้น หรือทริกเกอร์สิ่งอื่นที่ไม่ขึ้นอยู่กับพารามิเตอร์การเรียกกลับ
- การติดตั้งใช้งาน Listener ควรระบุสิ่งที่ทริกเกอร์เหตุการณ์ในชื่อเมธอดอย่างชัดเจนและอ่านได้
- Listener จะรายงานไปยังระบบวิเคราะห์ที่ต้องทราบเกี่ยวกับเหตุการณ์แต่ละรายการและการเปลี่ยนแปลงสถานะทั้งหมด
ควรใช้ onEvents(Player player, Events events) ทั่วไปในกรณีต่อไปนี้
- ผู้ฟังต้องการเรียกใช้ตรรกะเดียวกันสำหรับเหตุการณ์หลายรายการ เช่น การอัปเดต UI สำหรับทั้ง
onPlaybackStateChangedและonPlayWhenReadyChanged - Listener ต้องเข้าถึงออบเจ็กต์
Playerเพื่อทริกเกอร์เหตุการณ์เพิ่มเติม เช่น การกรอหลังจากเปลี่ยนรายการสื่อ - ผู้ฟังต้องการใช้ค่าสถานะหลายค่าที่รายงานผ่าน
การเรียกกลับแยกกัน หรือใช้ร่วมกับ
Playerเมธอด Getter เช่น การใช้Player.getCurrentWindowIndex()กับTimelineที่ระบุไว้ในonTimelineChangedจะปลอดภัยเมื่อใช้จากภายในแฮนเดิลonEventsเท่านั้น - ผู้ฟังสนใจว่าเหตุการณ์เกิดขึ้นพร้อมกันอย่างสมเหตุสมผลหรือไม่
เช่น
onPlaybackStateChangedเป็นSTATE_BUFFERINGเนื่องจาก การเปลี่ยนรายการสื่อ
ในบางกรณี ผู้ฟังอาจต้องรวมการเรียกกลับแต่ละรายการกับการเรียกกลับonEventsทั่วไป เช่น เพื่อบันทึกเหตุผลของการเปลี่ยนแปลงรายการสื่อด้วย onMediaItemTransition แต่จะดำเนินการได้เมื่อใช้การเปลี่ยนแปลงสถานะทั้งหมดร่วมกันใน onEvents เท่านั้น
กำลังใช้ AnalyticsListener
เมื่อใช้ ExoPlayer คุณจะลงทะเบียน AnalyticsListener กับเพลเยอร์ได้
โดยเรียกใช้ addAnalyticsListener การติดตั้งใช้งาน AnalyticsListener สามารถ
ตรวจสอบเหตุการณ์โดยละเอียดซึ่งอาจมีประโยชน์สําหรับการวิเคราะห์และการบันทึก
ได้ โปรดดูรายละเอียดเพิ่มเติมในหน้าข้อมูลวิเคราะห์
กำลังใช้ EventLogger
EventLogger คือ AnalyticsListener ที่ห้องสมุดจัดหาให้โดยตรงเพื่อ
วัตถุประสงค์ในการบันทึก เพิ่ม EventLogger ใน ExoPlayer เพื่อเปิดใช้การบันทึกเพิ่มเติมที่มีประโยชน์
ด้วยบรรทัดเดียว
Kotlin
player.addAnalyticsListener(EventLogger())
Java
player.addAnalyticsListener(new EventLogger());
ดูรายละเอียดเพิ่มเติมได้ที่หน้าการบันทึกการแก้ไขข้อบกพร่อง
ทริกเกอร์เหตุการณ์ที่ตำแหน่งการเล่นที่ระบุ
Use Case บางอย่างกำหนดให้ต้องทริกเกอร์เหตุการณ์ที่ตำแหน่งการเล่นที่ระบุ ซึ่งรองรับการใช้งานโดยใช้ 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();