ยกระดับการเล่นสื่อ: ขอแนะนำการโหลดล่วงหน้าด้วย Media3 - ตอนที่ 1
อ่าน 8 นาที
ในแอปที่เน้นสื่อเป็นหลักในปัจจุบัน การมอบประสบการณ์การเล่นที่ราบรื่นและไม่สะดุดเป็นสิ่งสำคัญที่จะช่วยให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่ยอดเยี่ยม ผู้ใช้คาดหวังว่าวิดีโอจะเริ่มเล่นทันทีและเล่นได้อย่างราบรื่นโดยไม่มีการหยุดชั่วคราว
ความท้าทายหลักคือเวลาในการตอบสนอง โดยปกติแล้ว โปรแกรมเล่นวิดีโอจะเริ่มทำงาน (เชื่อมต่อ ดาวน์โหลด แยกวิเคราะห์ บัฟเฟอร์) หลังจากที่ผู้ใช้เลือกรายการที่จะเล่น แนวทางเชิงรับนี้ช้าเกินไปสำหรับบริบทของวิดีโอแบบสั้นในปัจจุบัน ดังนั้นวิธีแก้ปัญหาคือการใช้แนวทางเชิงรุก เราต้องคาดการณ์ว่าผู้ใช้จะดูอะไรต่อไปและเตรียมเนื้อหาให้พร้อมล่วงหน้า ซึ่งเป็นหัวใจสำคัญของการโหลดล่วงหน้า
ประโยชน์หลักของการโหลดล่วงหน้ามีดังนี้
- 🚀 วิดีโอเริ่มเล่นเร็วขึ้น: วิดีโอพร้อมเล่นแล้ว ซึ่งจะช่วยให้การเปลี่ยนระหว่างรายการต่างๆ เป็นไปได้เร็วขึ้นและเริ่มเล่นได้ทันทีมากขึ้น
- 📉 การบัฟเฟอร์ลดลง: การโหลดข้อมูลล่วงหน้าจะช่วยลดโอกาสที่การเล่นจะหยุดชะงัก เช่น จากปัญหาการเชื่อมต่อเครือข่าย
- ✨ ประสบการณ์การใช้งานของผู้ใช้ราบรื่นขึ้น: การผสมผสานระหว่างการเริ่มเล่นที่เร็วขึ้นและการบัฟเฟอร์ที่น้อยลงจะช่วยให้ผู้ใช้โต้ตอบได้อย่างราบรื่นและสนุกสนานมากขึ้น
ในซีรีส์ 3 ตอนนี้ เราจะแนะนำและเจาะลึกยูทิลิตีที่มีประสิทธิภาพของ Media3 สำหรับการโหลด (ล่วงหน้า) คอมโพเนนต์
- ในตอนที่ 1 เราจะพูดถึงพื้นฐาน ได้แก่ การทำความเข้าใจกลยุทธ์การโหลดล่วงหน้าที่แตกต่างกันซึ่งมีอยู่ใน Media3, การเปิดใช้ PreloadConfiguration และการตั้งค่า DefaultPreloadManager รวมถึงการเปิดใช้แอปให้โหลดรายการล่วงหน้า เมื่ออ่านบล็อกนี้จบแล้ว คุณจะสามารถโหลดล่วงหน้าและเล่นรายการสื่อด้วยการจัดอันดับและระยะเวลาที่กำหนดค่าไว้
- ใน ตอนที่ 2 เราจะพูดถึงหัวข้อขั้นสูงเพิ่มเติมของ DefaultPreloadManager ได้แก่ การใช้ Listener สำหรับข้อมูลวิเคราะห์, การสำรวจแนวทางปฏิบัติแนะนำที่พร้อมใช้งานจริง เช่น รูปแบบหน้าต่างแบบเลื่อน และคอมโพเนนต์ที่แชร์ที่กำหนดเองของ DefaultPreloadManager และ ExoPlayer
- ในตอนที่ 3 เราจะเจาะลึกการแคชในดิสก์ด้วย DefaultPreloadManager
การโหลดล่วงหน้ามาช่วยแล้ว 🦸♀️
แนวคิดหลักเบื้องหลังการโหลดล่วงหน้าคือการโหลดเนื้อหาสื่อก่อนที่คุณจะต้องการ เมื่อผู้ใช้ปัดไปที่วิดีโอถัดไป ระบบจะดาวน์โหลดและเตรียมส่วนแรกของวิดีโอไว้ให้พร้อมเล่นทันที
ลองนึกถึงร้านอาหาร ห้องครัวที่วุ่นวายจะไม่รอให้มีออร์เดอร์ก่อนจึงจะเริ่มหั่นหัวหอม 🧅 แต่จะเตรียมงานล่วงหน้า การโหลดล่วงหน้าก็เหมือนกับการเตรียมงานสำหรับโปรแกรมเล่นวิดีโอ
เมื่อเปิดใช้ การโหลดล่วงหน้าจะช่วยลดเวลาในการตอบสนองเมื่อผู้ใช้ข้ามไปยังรายการถัดไปก่อนที่บัฟเฟอร์การเล่นจะไปถึงรายการถัดไป ระบบจะเตรียมช่วงแรกของหน้าต่างถัดไปและบัฟเฟอร์ตัวอย่างวิดีโอ เสียง และข้อความ จากนั้นจะจัดคิวช่วงที่โหลดล่วงหน้าไว้ในโปรแกรมเล่น โดยมีตัวอย่างที่บัฟเฟอร์ไว้พร้อมใช้งานทันทีและพร้อมที่จะส่งไปยังตัวแปลงสัญญาณเพื่อแสดงผล
ใน Media3 มี API หลัก 2 รายการสำหรับการโหลดล่วงหน้า ซึ่งแต่ละรายการเหมาะกับ Use Case ที่แตกต่างกัน การเลือก API ที่เหมาะสมคือขั้นตอนแรก
1. การโหลดรายการเพลย์ลิสต์ล่วงหน้าด้วย PreloadConfiguration
วิธีนี้เป็นวิธีที่ง่าย เหมาะสำหรับสื่อเชิงเส้นและตามลำดับ เช่น เพลย์ลิสต์ที่ลำดับการเล่นคาดการณ์ได้ (เช่น ซีรีส์ตอนต่างๆ) คุณให้รายการสื่อทั้งหมดแก่โปรแกรมเล่นโดยใช้ API เพลย์ลิสต์ playlist ของ ExoPlayer และตั้งค่า PreloadConfiguration สำหรับโปรแกรมเล่น จากนั้นโปรแกรมเล่นจะโหลดรายการถัดไปในลำดับล่วงหน้าโดยอัตโนมัติตามที่กำหนดค่าไว้ API นี้พยายามเพิ่มประสิทธิภาพเวลาในการตอบสนองเมื่อผู้ใช้ข้ามไปยังรายการถัดไปก่อนที่บัฟเฟอร์การเล่นจะซ้อนทับกับรายการถัดไป
ระบบจะเริ่มโหลดล่วงหน้าก็ต่อเมื่อไม่มีการโหลดสื่อสำหรับการเล่นที่กำลังดำเนินอยู่ ซึ่งจะช่วยป้องกันไม่ให้การโหลดล่วงหน้าแย่งแบนด์วิดท์กับการเล่นหลัก
หากยังไม่แน่ใจว่าคุณต้องโหลดล่วงหน้าหรือไม่ API นี้เป็นตัวเลือกที่ยอดเยี่ยมและทำได้ง่ายในการลองใช้
player.preloadConfiguration =
PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)ด้วย PreloadConfiguration ด้านบน โปรแกรมเล่นจะพยายามโหลดสื่อล่วงหน้า 5 วินาทีสำหรับรายการถัดไปในเพลย์ลิสต์
เมื่อเลือกใช้แล้ว คุณสามารถปิดการโหลดเพลย์ลิสต์ล่วงหน้าได้อีกครั้งโดยใช้ PreloadConfiguration.DEFAULT เพื่อปิดใช้การโหลดเพลย์ลิสต์ล่วงหน้า
player.preloadConfiguration = PreloadConfiguration.DEFAULT
2. การโหลดรายการแบบไดนามิกล่วงหน้าด้วย PreloadManager
สำหรับ UI แบบไดนามิก เช่น ฟีดแนวตั้งหรือภาพสไลด์ ซึ่งรายการ "ถัดไป" จะกำหนดโดยการโต้ตอบของผู้ใช้ API PreloadManager เหมาะสมกว่า API นี้เป็นคอมโพเนนต์แบบสแตนด์อโลนใหม่ที่มีประสิทธิภาพภายในไลบรารี Media3 ExoPlayer ซึ่งออกแบบมาโดยเฉพาะเพื่อโหลดล่วงหน้า โดยจะจัดการคอลเล็กชัน MediaSource ที่เป็นไปได้ โดยจัดลำดับความสำคัญตามความใกล้เคียงกับตำแหน่งปัจจุบันของผู้ใช้ และให้การควบคุมแบบละเอียด เกี่ยวกับสิ่งที่ต้องโหลดล่วงหน้า ซึ่งเหมาะสำหรับสถานการณ์ที่ซับซ้อน เช่น ฟีดแบบไดนามิกของวิดีโอแบบสั้น
การตั้งค่า PreloadManager
DefaultPreloadManager เป็นการใช้งานมาตรฐานสำหรับ PreloadManager
ตัวสร้าง DefaultPreloadManager สามารถสร้างทั้ง DefaultPreloadManager และอินสแตนซ์ ExoPlayer ที่จะเล่นเนื้อหาที่โหลดล่วงหน้า หากต้องการสร้าง DefaultPreloadManager คุณจะต้องส่ง TargetPreloadStatusControl ซึ่งเครื่องมือจัดการการโหลดล่วงหน้าจะใช้เพื่อค้นหาปริมาณที่จะโหลดสำหรับรายการ เราจะอธิบายและกำหนดตัวอย่าง TargetPreloadStatusControl ในส่วนด้านล่าง
val preloadManagerBuilder = DefaultPreloadManager.Builder(context, targetPreloadStatusControl) val preloadManager = val preloadManagerBuilder.build() // Build ExoPlayer with DefaultPreloadManager.Builder val player = preloadManagerBuilder.buildExoPlayer()
คุณต้องใช้ เครื่องมือสร้าง เดียวกันสำหรับทั้ง ExoPlayer และ DefaultPreloadManager เพื่อให้มั่นใจว่าคอมโพเนนต์เบื้องหลังจะแชร์กันอย่างถูกต้อง
เท่านี้ก็เรียบร้อย! ตอนนี้คุณมีเครื่องมือจัดการที่พร้อมรับคำสั่งแล้ว
การกำหนดค่าระยะเวลาและการจัดอันดับด้วย TargetPreloadStatusControl
จะเกิดอะไรขึ้นหากคุณต้องการโหลดวิดีโอล่วงหน้า เช่น 10 วินาที คุณสามารถระบุตำแหน่งของรายการสื่อในภาพสไลด์ได้ และ DefaultPreloadManager จะจัดลำดับความสำคัญในการโหลดรายการตามความใกล้เคียงกับรายการที่ผู้ใช้กำลังเล่น
หากต้องการควบคุมระยะเวลาที่จะโหลดล่วงหน้าสำหรับรายการ คุณสามารถระบุได้ด้วย DefaultPreloadManager.PreloadStatus ที่คุณส่งคืน
ตัวอย่างเช่น
- รายการ "A" มีลำดับความสำคัญสูงสุด ให้โหลดวิดีโอ 5 วินาที
- รายการ "B" มีลำดับความสำคัญปานกลาง แต่เมื่อถึงรายการนี้ ให้โหลดวิดีโอ 3 วินาที
- รายการ "C" มีลำดับความสำคัญน้อยกว่า ให้โหลดเฉพาะแทร็ก
- รายการ "D" มีลำดับความสำคัญน้อยกว่า ให้เตรียมไว้เท่านั้น
- รายการอื่นๆ อยู่ไกล ไม่ต้องโหลดล่วงหน้า
การควบคุมแบบละเอียดนี้จะช่วยให้คุณเพิ่มประสิทธิภาพการใช้ทรัพยากร ซึ่งเราขอแนะนำให้ทำเพื่อการเล่นที่ราบรื่น
import androidx.media3.exoplayer.DefaultPreloadManager.PreloadStatus
class MyTargetPreloadStatusControl(
currentPlayingIndex: Int = C.INDEX_UNSET
) : TargetPreloadStatusControl<Int,PreloadStatus> {
// The app is responsible for updating this based on UI state
override fun getTargetPreloadStatus(index: Int): PreloadStatus? {
val distance = index - currentPlayingIndex
// Adjacent items (Next): preload 5 seconds
if (distance == 1) {
// Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and suggest loading // 5000ms from the default start position
return PreloadStatus.specifiedRangeLoaded(5000L)
}
// Adjacent items (Previous): preload 3 seconds
else if (distance == -1) {
// Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED //and suggest loading 3000ms from the default start position
return PreloadStatus.specifiedRangeLoaded(3000L)
}
// Items two positions away: just select tracks
else if (distance) == 2) {
// Return a PreloadStatus that is labelled by STAGE_TRACKS_SELECTED
return PreloadStatus.TRACKS_SELECTED
}
// Items four positions away: just select prepare
else if (abs(distance) <= 4) {
// Return a PreloadStatus that is labelled by STAGE_SOURCE_PREPARED
return PreloadStatus.SOURCE_PREPARED
}
// All other items are too far away
return null
}
}เคล็ดลับ: PreloadManager สามารถโหลดทั้งรายการก่อนหน้าและรายการถัดไปล่วงหน้าได้ ในขณะที่ PreloadConfiguration จะดูเฉพาะรายการถัดไปเท่านั้น
การจัดการรายการที่โหลดล่วงหน้า
เมื่อสร้างเครื่องมือจัดการแล้ว คุณก็เริ่มบอกเครื่องมือจัดการได้ว่าจะให้ทำอะไร เมื่อผู้ใช้เลื่อนดูฟีด คุณจะระบุวิดีโอที่จะมาถึงและเพิ่มวิดีโอเหล่านั้นลงในเครื่องมือจัดการ การโต้ตอบกับ PreloadManager เป็นการสนทนาที่ขับเคลื่อนด้วยสถานะระหว่าง UI กับเครื่องมือโหลดล่วงหน้า
1. เพิ่มรายการสื่อ
เมื่อป้อนข้อมูลในฟีด คุณต้องแจ้งให้ เครื่องมือจัดการ ทราบเกี่ยวกับสื่อที่ต้องติดตาม หากเพิ่งเริ่มต้น คุณสามารถเพิ่มรายการทั้งหมดที่ต้องการโหลดล่วงหน้าได้ จากนั้นคุณจะเพิ่มรายการเดียวลงในรายการได้ตามต้องการ คุณสามารถควบคุมรายการที่อยู่ในรายการโหลดล่วงหน้าได้อย่างเต็มที่ ซึ่งหมายความว่าคุณต้องจัดการสิ่งที่เพิ่มและนำออกจากเครื่องมือจัดการด้วย
val initialMediaItems = pullMediaItemsFromService(/* count= */ 20)
for (index in 0 until initialMediaItems.size) {
preloadManager.add(
initialMediaItems.get(index),index)
)
}ตอนนี้เครื่องมือจัดการจะเริ่มดึงข้อมูลสำหรับ MediaItem นี้ในเบื้องหลัง
หลังจากเพิ่มแล้ว ให้บอกเครื่องมือจัดการให้ประเมินรายการใหม่ (บอกเป็นนัยว่ามีการเปลี่ยนแปลง เช่น การเพิ่ม/ นำรายการออก หรือผู้ใช้เปลี่ยนไปเล่นรายการใหม่)
preloadManager.invalidate()
2. ดึงและเล่นรายการ
นี่คือตรรกะการเล่นหลัก เมื่อผู้ใช้ตัดสินใจเล่นวิดีโอนั้น คุณไม่จำเป็นต้องสร้าง MediaSource ใหม่ แต่ให้ขอ PreloadManager สำหรับรายการที่เตรียมไว้แล้ว คุณสามารถดึง MediaSource จาก PreloadManager ได้โดยใช้ MediaItem
หากรายการที่ดึงมาจาก PreloadManager เป็น Null แสดงว่า mediaItem ยังไม่ได้โหลดล่วงหน้าหรือเพิ่มลงใน PreloadMamager ดังนั้นคุณจึงเลือกที่จะตั้งค่า mediaItem โดยตรง
// When a media item is about to display on the screen
val mediaSource = preloadManager.getMediaSource(mediaItem)
if (mediaSource!= null) {
player.setMediaSource(mediaSource)
} else {
// If mediaSource is null, that mediaItem hasn't been added yet.
// So, send it directly to the player.
player.setMediaItem(mediaItem)
}
player.prepare()
// When the media item is displaying at the center of the screen
player.play()การเตรียม MediaSource ที่ดึงมาจาก PreloadManager จะช่วยให้คุณเปลี่ยนจากการโหลดล่วงหน้าเป็นการเล่นได้อย่างราบรื่น โดยใช้ข้อมูลที่อยู่ในหน่วยความจำอยู่แล้ว ซึ่งจะช่วยให้เวลาเริ่มต้นเร็วขึ้น
3. ซิงค์ดัชนีปัจจุบันกับ UI
เนื่องจากฟีด / รายการของเราอาจเป็นแบบไดนามิก จึงควรแจ้งให้ PreloadManager ทราบถึงดัชนีการเล่นปัจจุบันเพื่อให้เครื่องมือจัดการจัดลำดับความสำคัญในการโหลดล่วงหน้าสำหรับรายการที่อยู่ใกล้กับดัชนีปัจจุบันมากที่สุดเสมอ
preloadManager.setCurrentPlayingIndex(currentIndex) // Need to call invalidate() to update the priorities preloadManager.invalidate()
4. นำรายการออก
คุณควรนำรายการที่เครื่องมือจัดการไม่จำเป็นต้องติดตามออกเพื่อให้เครื่องมือจัดการทำงานได้อย่างมีประสิทธิภาพ เช่น รายการที่อยู่ไกลจากตำแหน่งปัจจุบันของผู้ใช้
// When an item is too far from the current playing index preloadManager.remove(mediaItem)
หากต้องการล้างรายการทั้งหมดพร้อมกัน คุณสามารถเรียกใช้ preloadManager.reset()
5. ปล่อยเครื่องมือจัดการ
เมื่อไม่ต้องการใช้ PreloadManager อีกต่อไป (เช่น เมื่อ UI ถูกทำลาย) คุณต้องปล่อยเครื่องมือจัดการเพื่อเพิ่มพื้นที่ว่างให้กับทรัพยากร ตำแหน่งที่เหมาะสมในการดำเนินการนี้คือตำแหน่งที่คุณปล่อยทรัพยากรของ Player อยู่แล้ว เราขอแนะนำให้ปล่อยเครื่องมือจัดการก่อน Player เนื่องจาก Player จะเล่นต่อไปได้หากคุณไม่ต้องการโหลดล่วงหน้าอีก
// In your Activity's onDestroy() or Composable's onDispose preloadManager.release()
ช่วงเวลาสาธิตการใช้งาน
ดูการใช้งานจริง 👍
ในการสาธิตด้านล่าง เราจะเห็นผลกระทบของ PreloadManager ทางด้านขวา ซึ่งมีเวลาโหลดที่เร็วกว่า ในขณะที่ด้านซ้ายแสดงประสบการณ์การใช้งานที่มีอยู่ นอกจากนี้ คุณยังดูตัวอย่างโค้ด sample สำหรับการสาธิตได้ด้วย (โบนัส: ระบบจะแสดงเวลาในการตอบสนองเริ่มต้นสำหรับวิดีโอทุกรายการด้วย)
ขั้นตอนต่อไปคือ
และนี่คือตอนที่ 1 ตอนนี้คุณมีเครื่องมือในการสร้างระบบการโหลดล่วงหน้าแบบไดนามิกแล้ว คุณสามารถใช้ PreloadConfiguration เพื่อโหลดรายการถัดไปของเพลย์ลิสต์ล่วงหน้าใน ExoPlayer หรือตั้งค่า DefaultPreloadManager เพิ่มและนำรายการออกได้ทันที กำหนดค่าสถานะการโหลดล่วงหน้าเป้าหมาย และดึงเนื้อหาที่โหลดล่วงหน้ามาเล่นได้อย่างถูกต้อง
ใน ตอนที่ 2 เราจะเจาะลึก DefaultPreloadManager เราจะสำรวจวิธีฟังเหตุการณ์การโหลดล่วงหน้า พูดคุยเกี่ยวกับแนวทางปฏิบัติแนะนำ เช่น การใช้หน้าต่างแบบเลื่อนเพื่อหลีกเลี่ยงปัญหาหน่วยความจำ และดูคอมโพเนนต์ที่แชร์ที่กำหนดเองของ ExoPlayer และ DefaultPreloadManager
คุณมีความคิดเห็นที่จะ แชร์ไหม เรายินดีรับฟังความคิดเห็นจากคุณ
โปรดติดตามชมและไปทำให้แอปของคุณเร็วขึ้น 🚀
-
ข่าวสารเกี่ยวกับผลิตภัณฑ์ยินดีต้อนรับสู่ตอนที่ 2 ของซีรีส์ 3 ตอนเกี่ยวกับการโหลดสื่อล่วงหน้าด้วย Media3 ซีรีส์นี้ออกแบบมาเพื่อแนะนำคุณตลอดกระบวนการสร้างประสบการณ์การใช้งานสื่อที่มีการตอบสนองสูงและมีเวลาในการตอบสนองต่ำในแอป Android
Mayuri Khinvasara Khabya • อ่าน 9 นาที -
ข่าวสารเกี่ยวกับผลิตภัณฑ์การมอบประสบการณ์การใช้งานออนไลน์ที่ปลอดภัยและการปกป้องผู้ใช้จากอันตรายเป็นสิ่งสำคัญอันดับแรกของ Google Play
Paul Feng • อ่าน 2 นาที -
ข่าวสารเกี่ยวกับผลิตภัณฑ์วันนี้เราจะฉลองครบรอบ 5 ปีอย่างเป็นทางการนับตั้งแต่เปิดตัว Jetpack Compose 1.0 ตั้งแต่เวอร์ชัน 1.0 ที่ประกาศเมื่อวันที่ 28 กรกฎาคม 2021 ไปจนถึงเวอร์ชันล่าสุด 1.11 เราได้เห็น API พัฒนาไปอย่างมากในช่วงหลายปีที่ผ่านมา และเราขอใช้โอกาสนี้ในการเฉลิมฉลอง
Rebecca Franks, Nick Butcher, Loryn Hairston • อ่าน 5 นาที
รับข้อมูลเชิงลึกล่าสุดเกี่ยวกับการพัฒนา Android ส่งตรงถึงกล่องจดหมายของคุณ ทุกสัปดาห์