ข่าวสารผลิตภัณฑ์

ยกระดับการเล่นสื่อ: เจาะลึก PreloadManager ของ Media3 - ตอนที่ 2

ใช้เวลาอ่าน 9 นาที
Mayuri Khinvasara Khabya
วิศวกรนักพัฒนาซอฟต์แวร์สัมพันธ์

ยินดีต้อนรับสู่ตอนที่ 2 ของซีรีส์ 3 ตอนเกี่ยวกับการโหลดสื่อล่วงหน้าด้วย Media3 ซีรีส์นี้ออกแบบมาเพื่อแนะนำขั้นตอนการสร้างประสบการณ์การใช้งานสื่อที่ตอบสนองสูงและมีเวลาในการตอบสนองต่ำในแอป Android

  • ตอนที่ 1: บทนำเกี่ยวกับการโหลดล่วงหน้าด้วย Media3 ครอบคลุมพื้นฐาน เราได้สำรวจความแตกต่างระหว่าง PreloadConfiguration สำหรับเพลย์ลิสต์แบบง่ายกับ DefaultPreloadManager ที่มีประสิทธิภาพมากกว่าสำหรับอินเทอร์เฟซผู้ใช้แบบไดนามิก คุณได้เรียนรู้วิธีใช้วงจรการทำงานของ API ขั้นพื้นฐาน ได้แก่ การเพิ่มสื่อด้วย add() การดึงข้อมูล MediaSource ที่เตรียมไว้ด้วย getMediaSource() การจัดการลำดับความสำคัญด้วย setCurrentPlayingIndex() และ invalidate() รวมถึงการปล่อยทรัพยากรด้วย remove() และ release()
  • ตอนที่ 2 (โพสต์นี้): ในบล็อกนี้ เราจะสำรวจความสามารถขั้นสูงของ DefaultPreloadManager เราจะพูดถึงวิธีรับข้อมูลเชิงลึกด้วย PreloadManagerListener, การใช้แนวทางปฏิบัติแนะนำที่พร้อมใช้งานจริง เช่น การแชร์คอมโพเนนต์หลักกับ ExoPlayer และการใช้รูปแบบหน้าต่างเลื่อนเพื่อจัดการหน่วยความจำอย่างมีประสิทธิภาพ
  • ตอนที่ 3: ตอนสุดท้ายของซีรีส์นี้จะเจาะลึกการผสานรวม PreloadManager กับแคชดิสก์แบบถาวร ซึ่งจะช่วยให้คุณลดการใช้ข้อมูลด้วยการจัดการทรัพยากรและมอบประสบการณ์การใช้งานที่ราบรื่น

หากคุณยังไม่เคยใช้การโหลดล่วงหน้าใน Media3 เราขอแนะนำให้อ่าน ตอนที่ 1 ก่อนดำเนินการต่อ สำหรับผู้ที่พร้อมจะก้าวข้ามพื้นฐานแล้ว มาสำรวจวิธีปรับปรุงการใช้การเล่นสื่อกัน

การรับฟัง: ดึงข้อมูลวิเคราะห์ด้วย PreloadManagerListener

เมื่อต้องการเปิดตัวฟีเจอร์ในเวอร์ชันที่ใช้งานจริง ในฐานะนักพัฒนาแอป คุณก็ต้องการทำความเข้าใจและรวบรวมข้อมูลวิเคราะห์เบื้องหลังฟีเจอร์นั้นด้วย คุณจะมั่นใจได้อย่างไรว่ากลยุทธ์การโหลดล่วงหน้ามีประสิทธิภาพในสภาพแวดล้อมจริง การตอบคำถามนี้ต้องใช้ข้อมูลเกี่ยวกับอัตราความสำเร็จ ความล้มเหลว และประสิทธิภาพ อินเทอร์เฟซ PreloadManagerListener เป็นกลไกหลักในการรวบรวมข้อมูลนี้

PreloadManagerListener มี 2 การเรียกกลับที่สำคัญซึ่งให้ข้อมูลเชิงลึกที่สำคัญเกี่ยวกับกระบวนการและสถานะการโหลดล่วงหน้า

  • onCompleted(MediaItem mediaItem): การเรียกกลับนี้จะเรียกใช้เมื่อคำขอโหลดล่วงหน้าเสร็จสมบูรณ์ตามที่กำหนดโดย TargetPreloadStatusControl
  • onError(PreloadException error): การเรียกกลับนี้อาจมีประโยชน์สำหรับการแก้ไขข้อบกพร่องและการตรวจสอบ โดยจะเรียกใช้เมื่อการโหลดล่วงหน้าล้มเหลวและแสดงข้อยกเว้นที่เกี่ยวข้อง

คุณสามารถลงทะเบียน Listener ได้ด้วยการเรียกใช้เมธอดเดียวตามที่แสดงในโค้ดตัวอย่างต่อไปนี้

val preloadManagerListener = object : PreloadManagerListener {
    override fun onCompleted(mediaItem: MediaItem) {
        // Log success for analytics. 
        Log.d("PreloadAnalytics", "Preload completed for $mediaItem")
    }

    override fun onError( preloadError: PreloadException) {
        // Log the specific error for debugging and monitoring.
        Log.e("PreloadAnalytics", "Preload error ", preloadError)
    }
}

preloadManager.addListener(preloadManagerListener)

การดึงข้อมูลเชิงลึกจาก Listener

คุณสามารถเชื่อมต่อการเรียกกลับของ Listener เหล่านี้กับไปป์ไลน์ข้อมูลวิเคราะห์ การส่งต่อเหตุการณ์เหล่านี้ไปยังเครื่องมือข้อมูลวิเคราะห์จะช่วยให้คุณตอบคำถามสำคัญๆ ได้ เช่น

  • อัตราความสำเร็จในการโหลดล่วงหน้าของเราคือเท่าใด (อัตราส่วนของเหตุการณ์ onCompleted ต่อจำนวนครั้งที่พยายามโหลดล่วงหน้าทั้งหมด)
  • CDN หรือรูปแบบวิดีโอใดมีอัตราข้อผิดพลาดสูงสุด (โดยการแยกวิเคราะห์ข้อยกเว้นจาก onError)
  • อัตราข้อผิดพลาดในการโหลดล่วงหน้าของเราคือเท่าใด (อัตราส่วนของเหตุการณ์ onError ต่อจำนวนครั้งที่พยายามโหลดล่วงหน้าทั้งหมด)

ข้อมูลนี้จะให้ความคิดเห็นเชิงปริมาณเกี่ยวกับกลยุทธ์การโหลดล่วงหน้า ซึ่งช่วยให้คุณทำการทดสอบ A/B และปรับปรุงประสบการณ์ของผู้ใช้โดยอิงตามข้อมูลได้ นอกจากนี้ ข้อมูลนี้ยังช่วยให้คุณปรับระยะเวลาการโหลดล่วงหน้า และจำนวนวิดีโอที่ต้องการโหลดล่วงหน้า รวมถึงบัฟเฟอร์ที่จัดสรรได้อย่างชาญฉลาด

มากกว่าการแก้ไขข้อบกพร่อง: การใช้ onError สำหรับการสำรอง UI อย่างราบรื่น

การโหลดล่วงหน้าล้มเหลวเป็นตัวบ่งชี้ที่ชัดเจนว่าผู้ใช้จะพบเหตุการณ์การบัฟเฟอร์ในเร็วๆ นี้ การเรียกกลับ onError ช่วยให้คุณตอบสนองได้อย่างรวดเร็ว แทนที่จะบันทึกข้อผิดพลาด คุณสามารถปรับ UI ได้ ตัวอย่างเช่น หากวิดีโอที่จะเล่นต่อไปโหลดล่วงหน้าไม่สำเร็จ แอปพลิเคชันของคุณอาจปิดใช้การเล่นอัตโนมัติสำหรับการปัดครั้งถัดไป ซึ่งผู้ใช้จะต้องแตะเพื่อเริ่มเล่น

นอกจากนี้ การตรวจสอบประเภท PreloadException ยังช่วยให้คุณกำหนดกลยุทธ์การลองใหม่ที่ชาญฉลาดมากขึ้นได้ แอปสามารถเลือกที่จะนำแหล่งที่มาที่ล้มเหลวออกจากตัวจัดการทันทีโดยอิงตามข้อความแสดงข้อผิดพลาดหรือรหัสสถานะ HTTP คุณจะต้องนำรายการออกจากสตรีม UI ตามความเหมาะสมเพื่อไม่ให้ปัญหาการโหลดส่งผลต่อประสบการณ์ของผู้ใช้ นอกจากนี้ คุณยังรับข้อมูลที่ละเอียดยิ่งขึ้นจาก PreloadException เช่น HttpDataSourceException เพื่อตรวจสอบข้อผิดพลาดเพิ่มเติมได้ อ่านเพิ่มเติมเกี่ยวกับการแก้ปัญหา ExoPlayer

ระบบเพื่อน: เหตุใดจึงต้องแชร์คอมโพเนนต์กับ ExoPlayer

DefaultPreloadManager และ ExoPlayer ออกแบบมาให้ทำงานร่วมกัน โดยต้องแชร์คอมโพเนนต์หลักหลายรายการเพื่อให้มั่นใจถึงความเสถียรและประสิทธิภาพ หากทำงานด้วยคอมโพเนนต์ที่แยกกันและไม่ประสานงานกัน อาจส่งผลต่อความปลอดภัยของเธรดและความสามารถในการใช้งานแทร็กที่โหลดล่วงหน้าในเพลเยอร์ เนื่องจากเราต้องตรวจสอบว่าแทร็กที่โหลดล่วงหน้าควรเล่นในเพลเยอร์ที่ถูกต้อง นอกจากนี้ คอมโพเนนต์ที่แยกกันอาจแย่งชิงทรัพยากรที่มีจำกัด เช่น แบนด์วิดท์เครือข่ายและหน่วยความจำ ซึ่งอาจทำให้ประสิทธิภาพลดลง ส่วนสำคัญของวงจรการทำงานคือการจัดการการกำจัดที่เหมาะสม โดยลำดับการกำจัดที่แนะนำคือการปล่อย PreloadManager ก่อน แล้วตามด้วย ExoPlayer

DefaultPreloadManager.Builder ออกแบบมาเพื่ออำนวยความสะดวกในการแชร์นี้และมี API สำหรับ สร้างอินสแตนซ์ทั้ง PreloadManager และอินสแตนซ์เพลเยอร์ที่ลิงก์ มาดูกันว่าเหตุใดจึงต้องแชร์คอมโพเนนต์ต่างๆ เช่น BandwidthMeter, LoadControl, TrackSelector, Looper ดูภาพแสดงการโต้ตอบของคอมโพเนนต์เหล่านี้กับการเล่น ExoPlayer

preloadManager2.png

การป้องกันความขัดแย้งด้านแบนด์วิดท์ด้วย BandwidthMeter ที่แชร์

BandwidthMeter จะประมาณแบนด์วิดท์เครือข่ายที่พร้อมใช้งานโดยอิงตามอัตราการโอนข้อมูลที่ผ่านมา หาก PreloadManager และเพลเยอร์ใช้คอมโพเนนต์ที่แยกกัน ทั้ง 2 คอมโพเนนต์จะไม่ทราบกิจกรรมเครือข่ายของกันและกัน ซึ่งอาจนำไปสู่สถานการณ์ที่ล้มเหลว ตัวอย่างเช่น พิจารณาสถานการณ์ที่ผู้ใช้กำลังดูวิดีโอ การเชื่อมต่อเครือข่ายของผู้ใช้แย่ลง และ MediaSource ที่โหลดล่วงหน้าเริ่มดาวน์โหลดวิดีโอที่จะเล่นต่อไปอย่างรวดเร็วพร้อมกัน กิจกรรมของ MediaSource ที่โหลดล่วงหน้าจะใช้แบนด์วิดท์ที่เพลเยอร์ที่ใช้งานอยู่ต้องการ ซึ่งทำให้วิดีโอที่กำลังเล่นอยู่หยุดชะงัก การหยุดชะงักระหว่างการเล่นเป็นความล้มเหลวที่สำคัญของประสบการณ์ของผู้ใช้

การแชร์ BandwidthMeter เดียวจะช่วยให้ TrackSelector เลือกแทร็กที่มีคุณภาพสูงสุดได้ตามสภาพเครือข่ายปัจจุบันและสถานะของบัฟเฟอร์ระหว่างการโหลดล่วงหน้าหรือการเล่น จากนั้น TrackSelector จะตัดสินใจอย่างชาญฉลาดเพื่อปกป้องเซสชันการเล่นที่ใช้งานอยู่และมอบประสบการณ์การใช้งานที่ราบรื่น

preloadManagerBuilder.setBandwidthMeter(customBandwidthMeter)

การรับประกันความสอดคล้องด้วยคอมโพเนนต์ LoadControl, TrackSelector, Renderer ที่แชร์ของ ExoPlayer

  • LoadControl: คอมโพเนนต์นี้กำหนดนโยบายการบัฟเฟอร์ เช่น จำนวนข้อมูลที่จะบัฟเฟอร์ก่อนเริ่มเล่น และเวลาที่จะเริ่มหรือหยุดโหลดข้อมูลเพิ่มเติม การแชร์ LoadControl จะช่วยให้การใช้หน่วยความจำของเพลเยอร์และ PreloadManager เป็นไปตามกลยุทธ์การบัฟเฟอร์ที่ประสานงานกันเพียงกลยุทธ์เดียวสำหรับสื่อที่โหลดล่วงหน้าและสื่อที่กำลังเล่นอยู่ ซึ่งจะช่วยป้องกันการแย่งชิงทรัพยากร คุณจะต้องจัดสรรขนาดบัฟเฟอร์อย่างชาญฉลาดโดยประสานงานกับจำนวนรายการที่โหลดล่วงหน้าและระยะเวลาการโหลดล่วงหน้า เพื่อให้มั่นใจถึงความสอดคล้อง ในกรณีที่มีการแย่งชิง เพลเยอร์จะจัดลำดับความสำคัญของการเล่นรายการปัจจุบันที่แสดงบนหน้าจอ เมื่อใช้ LoadControl ที่แชร์ ตัวจัดการการโหลดล่วงหน้าจะโหลดล่วงหน้าต่อไปตราบใดที่ไบต์บัฟเฟอร์เป้าหมายที่จัดสรรไว้สำหรับการโหลดล่วงหน้ายังไม่ถึงขีดจำกัดบน โดยจะไม่รอจนกว่าการโหลดสำหรับการเล่นจะเสร็จสมบูรณ์

หมายเหตุ: การแชร์ LoadControl ในเวอร์ชันล่าสุดของ Media3 (1.8) ช่วยให้มั่นใจได้ว่า Allocator จะแชร์กับ PreloadManager และเพลเยอร์ได้อย่างถูกต้อง การใช้ LoadControl เพื่อควบคุมการโหลดล่วงหน้าอย่างมีประสิทธิภาพเป็นฟีเจอร์ที่จะพร้อมใช้งานใน Media3 1.9 เวอร์ชันที่จะเปิดตัวในเร็วๆ นี้

preloadManagerBuilder.setLoadControl(customLoadControl)

  • TrackSelector: คอมโพเนนต์นี้มีหน้าที่เลือกแทร็กที่จะโหลดและเล่น (เช่น วิดีโอที่มีความละเอียดหนึ่งๆ หรือเสียงในภาษาหนึ่งๆ) การแชร์จะช่วยให้แทร็กที่เลือกไว้ระหว่างการโหลดล่วงหน้าเป็นแทร็กเดียวกับที่เพลเยอร์จะใช้ ซึ่งจะช่วยหลีกเลี่ยงสถานการณ์ที่สิ้นเปลือง เช่น การโหลดล่วงหน้าแทร็กวิดีโอ 480p แต่เพลเยอร์จะทิ้งแทร็กนั้นทันทีและดึงแทร็ก 720p มาเล่นแทน< br /> ตัวจัดการการโหลดล่วงหน้า**ไม่ควร** แชร์อินสแตนซ์เดียวกัน ของ TrackSelector กับเพลเยอร์ แต่ควรใช้ TrackSelector อินสแตนซ์แต่มีการใช้งานเหมือนกัน ที่แตกต่างกัน เราจึงตั้งค่า TrackSelectorFactory แทนที่จะเป็น TrackSelector ใน DefaultPreloadManager.Builder

preloadManagerBuilder.setTrackSelectorFactory(customTrackSelectorFactory)

  • Renderer: คอมโพเนนต์นี้มีหน้าที่ทำความเข้าใจความสามารถของเพลเยอร์โดยไม่ต้องสร้าง Renderer แบบเต็ม โดยจะตรวจสอบพิมพ์เขียวนี้เพื่อดูว่าเพลเยอร์สุดท้ายจะรองรับรูปแบบวิดีโอ เสียง และข้อความใดบ้าง ซึ่งจะช่วยให้เลือกและดาวน์โหลดแทร็กสื่อที่เข้ากันได้เท่านั้นได้อย่างชาญฉลาด และป้องกันการสิ้นเปลืองแบนด์วิดท์กับเนื้อหาที่เพลเยอร์เล่นไม่ได้

preloadManagerBuilder.setRenderersFactory(customRenderersFactory)

อ่านเกี่ยวกับคอมโพเนนต์ ExoPlayer เพิ่มเติม

กฎทอง: Playback Looper ทั่วไปที่ใช้ได้กับทุกอย่าง

คุณสามารถระบุเธรดที่เข้าถึงอินสแตนซ์ ExoPlayer ได้อย่างชัดเจนโดยส่ง Looper เมื่อสร้างเพลเยอร์ คุณสามารถค้นหา Looper ของเธรดที่ต้องเข้าถึงเพลเยอร์ได้โดยใช้ Player.getApplicationLooper การรักษา Looper ที่แชร์ระหว่างเพลเยอร์กับ PreloadManager จะรับประกันว่าการดำเนินการทั้งหมดในออบเจ็กต์สื่อที่แชร์เหล่านี้จะถูกทำให้เป็นอนุกรมในคิวข้อความของเธรดเดียว ซึ่งจะช่วยลดข้อบกพร่องที่เกิดจากการทำงานพร้อมกัน

การโต้ตอบทั้งหมดระหว่าง PreloadManager กับเพลเยอร์ที่มีแหล่งที่มาของสื่อที่จะโหลดหรือโหลดล่วงหน้าต้องเกิดขึ้นในเธรดการเล่นเดียวกัน การแชร์ Looper เป็นสิ่งจำเป็นสำหรับความปลอดภัยของเธรด ดังนั้นเราจึงต้องแชร์ PlaybackLooper ระหว่าง PreloadManager กับเพลเยอร์

PreloadManager จะเตรียมออบเจ็กต์ MediaSource ที่มีสถานะในเบื้องหลัง เมื่อโค้ด UI เรียกใช้ player.setMediaSource(mediaSource) คุณจะส่งต่อออบเจ็กต์ที่ซับซ้อนและมีสถานะนี้จาก MediaSource ที่โหลดล่วงหน้าไปยังเพลเยอร์ ในสถานการณ์นี้ ระบบจะย้าย PreloadMediaSource ทั้งหมดจากตัวจัดการไปยังเพลเยอร์ การโต้ตอบและการส่งต่อทั้งหมดนี้ควรเกิดขึ้นใน PlaybackLooper เดียวกัน

หาก PreloadManager และ ExoPlayer ทำงานในเธรดที่ต่างกัน อาจเกิดสภาวะการแข่งขันได้ เธรดของ PreloadManager อาจแก้ไขสถานะภายในของ MediaSource (เช่น การเขียนข้อมูลใหม่ลงในบัฟเฟอร์) ในขณะที่เธรดของเพลเยอร์พยายามอ่านข้อมูลจาก MediaSource ซึ่งจะนำไปสู่ลักษณะการทำงานที่คาดเดาไม่ได้และ IllegalStateException ที่แก้ไขข้อบกพร่องได้ยาก

preloadManagerBuilder.setPreloadLooper(playbackLooper)

มาดูกันว่าคุณจะแชร์คอมโพเนนต์ทั้งหมดข้างต้นระหว่าง ExoPlayer กับ DefaultPreloadManager ในการตั้งค่าได้อย่างไร

val preloadManagerBuilder =
DefaultPreloadManager.Builder(context, targetPreloadStatusControl)

// Optional - Share components between ExoPlayer and DefaultPreloadManager
preloadManagerBuilder
     .setBandwidthMeter(customBandwidthMeter)
     .setLoadControl(customLoadControl)
     .setMediaSourceFactory(customMediaSourceFactory)
     .setTrackSelectorFactory(customTrackSelectorFactory)
     .setRenderersFactory(customRenderersFactory)
     .setPreloadLooper(playbackLooper)

val preloadManager = val preloadManagerBuilder.build()

เคล็ดลับ: หากคุณใช้คอมโพเนนต์เริ่มต้นใน ExoPlayer เช่น DefaultLoadControl เป็นต้น คุณไม่จำเป็นต้องแชร์คอมโพเนนต์เหล่านั้นกับ DefaultPreloadManager อย่างชัดเจน เมื่อคุณสร้างอินสแตนซ์ ExoPlayer ผ่าน buildExoPlayer ของ DefaultPreloadManager.Builder คอมโพเนนต์เหล่านี้จะอ้างอิงถึงกันโดยอัตโนมัติ หากคุณใช้การใช้งานเริ่มต้นกับการกำหนดค่าเริ่มต้น แต่หากคุณใช้คอมโพเนนต์ที่กำหนดเองหรือการกำหนดค่าที่กำหนดเอง คุณควร แจ้งให้ DefaultPreloadManager ทราบ ผ่าน API ข้างต้น

การโหลดล่วงหน้าที่พร้อมใช้งานจริง: รูปแบบหน้าต่างเลื่อน

ในฟีดแบบไดนามิก ผู้ใช้สามารถเลื่อนดูเนื้อหาจำนวนมากได้ หากคุณเพิ่มวิดีโอลงใน DefaultPreloadManager อย่างต่อเนื่องโดยไม่มีกลยุทธ์การนำออกที่สอดคล้องกัน คุณจะทำให้เกิด OutOfMemoryError อย่างหลีกเลี่ยงไม่ได้ MediaSource ที่โหลดล่วงหน้าแต่ละรายการจะเก็บ SampleQueue ไว้ ซึ่งจะจัดสรรบัฟเฟอร์หน่วยความจำ เมื่อบัฟเฟอร์เหล่านี้สะสมกันมากขึ้นเรื่อยๆ ก็อาจทำให้พื้นที่ฮีปของแอปพลิเคชันหมดลง วิธีแก้ปัญหาคืออัลกอริทึมที่คุณอาจคุ้นเคยอยู่แล้ว ซึ่งเรียกว่าหน้าต่างเลื่อน รูปแบบหน้าต่างเลื่อนจะเก็บรายการจำนวนเล็กน้อยที่จัดการได้ไว้ในหน่วยความจำ ซึ่งอยู่ติดกับตำแหน่งปัจจุบันของผู้ใช้ในฟีดตามตรรกะ เมื่อผู้ใช้เลื่อน "หน้าต่าง" ของรายการที่จัดการไว้จะเลื่อนตามผู้ใช้ โดยเพิ่มรายการใหม่ที่เข้ามาในมุมมอง และนำรายการที่อยู่ไกลออก

slidingwindow.png

การใช้รูปแบบหน้าต่างเลื่อน

คุณต้องเข้าใจว่า PreloadManager ไม่มีเมธอด setWindowSize() ในตัว หน้าต่างเลื่อนเป็นรูปแบบการออกแบบที่คุณในฐานะนักพัฒนาแอปมีหน้าที่ต้องใช้เมธอด add() และ remove() แบบพื้นฐาน ตรรกะของแอปพลิเคชันต้องเชื่อมต่อเหตุการณ์ UI เช่น การเลื่อนหรือการเปลี่ยนหน้า กับการเรียก API เหล่านี้ หากต้องการข้อมูลอ้างอิงโค้ดสำหรับเรื่องนี้ เราได้ใช้รูปแบบหน้าต่างเลื่อนในตัวอย่าง Socialite ซึ่งรวมถึง PreloadManagerWrapper ที่เลียนแบบหน้าต่างเลื่อนด้วย

อย่าลืมเพิ่ม preloadManager.remove(mediaItem) ในการใช้งานเมื่อรายการไม่น่าจะปรากฏขึ้นในมุมมองของผู้ใช้ในเร็วๆ นี้ การไม่นำรายการที่ไม่อยู่ใกล้ผู้ใช้ออกเป็นสาเหตุหลักของปัญหาหน่วยความจำในการใช้งานการโหลดล่วงหน้า การเรียกใช้ remove() จะปล่อยทรัพยากรที่ช่วยให้การใช้งานหน่วยความจำของแอปอยู่ในขอบเขตและมีเสถียรภาพ

การปรับแต่งกลยุทธ์การโหลดล่วงหน้าที่จัดหมวดหมู่ด้วย TargetPreloadStatusControl

เมื่อกำหนดสิ่งที่ต้องโหลดล่วงหน้า (รายการในหน้าต่าง) แล้ว เราก็สามารถใช้กลยุทธ์ที่กำหนดไว้อย่างดีเพื่อกำหนดจำนวนที่จะโหลดล่วงหน้าสำหรับแต่ละรายการ เราได้เห็นวิธีใช้การตั้งค่า TargetPreloadStatusControl เพื่อให้ได้ความละเอียดนี้ใน ตอนที่ 1

โปรดจำไว้ว่ารายการที่ตำแหน่ง +/- 1 อาจมีโอกาสเล่นมากกว่ารายการที่ตำแหน่ง +/- 4 คุณสามารถจัดสรรทรัพยากร (เครือข่าย, CPU, หน่วยความจำ) ให้กับรายการที่ผู้ใช้มีแนวโน้มที่จะดูต่อไปได้มากขึ้น ซึ่งจะสร้างกลยุทธ์ "การโหลดล่วงหน้า" ตามความใกล้เคียง ซึ่งเป็นกุญแจสำคัญในการสร้างสมดุล ระหว่างการเล่นทันทีกับการใช้ทรัพยากรอย่างมีประสิทธิภาพ

คุณสามารถใช้ข้อมูลวิเคราะห์ผ่าน PreloadManagerListener ตามที่กล่าวไว้ในส่วนก่อนหน้าเพื่อกำหนดกลยุทธ์ระยะเวลาการโหลดล่วงหน้า

สรุปและขั้นตอนถัดไป

ตอนนี้คุณมีความรู้ขั้นสูงในการสร้างฟีดสื่อที่รวดเร็ว เสถียร และประหยัดทรัพยากรโดยใช้ DefaultPreloadManager ของ Media3 แล้ว

มาสรุปประเด็นสำคัญกัน

  • ใช้ PreloadManagerListener เพื่อรวบรวมข้อมูลเชิงลึกด้านข้อมูลวิเคราะห์และใช้การจัดการข้อผิดพลาดที่มีประสิทธิภาพ
  • ใช้ DefaultPreloadManager.Builder เดียวเสมอเพื่อสร้างทั้งอินสแตนซ์ตัวจัดการและเพลเยอร์ เพื่อให้มั่นใจว่าคอมโพเนนต์ที่สำคัญจะได้รับการแชร์
  • ใช้รูปแบบหน้าต่างเลื่อนโดยจัดการการเรียกใช้ add() และ remove() อย่างจริงจังเพื่อป้องกัน OutOfMemoryError
  • ใช้ TargetPreloadStatusControl เพื่อสร้างกลยุทธ์การโหลดล่วงหน้าแบบหลายระดับที่ชาญฉลาด ซึ่งสร้างสมดุลระหว่างประสิทธิภาพและการใช้ทรัพยากร

ขั้นตอนถัดไปในตอนที่ 3: การแคชด้วยสื่อที่โหลดล่วงหน้า

การโหลดข้อมูลล่วงหน้าลงในหน่วยความจำจะให้ประโยชน์ด้านประสิทธิภาพทันที แต่ก็อาจมีข้อเสีย เมื่อปิดแอปพลิเคชันหรือนำสื่อที่โหลดล่วงหน้าออกจากตัวจัดการ ข้อมูลจะหายไป หากต้องการเพิ่มประสิทธิภาพในระดับที่ถาวรมากขึ้น เราสามารถรวมการโหลดล่วงหน้ากับการแคชดิสก์ได้ ฟีเจอร์นี้อยู่ระหว่างการพัฒนาและจะพร้อมใช้งานในอีกไม่กี่เดือนข้างหน้า

คุณมีความคิดเห็นที่จะ แชร์ไหม เรายินดีรับฟังความคิดเห็นจากคุณ

โปรดติดตามข่าวสารและทำให้การเล่นวิดีโอเร็วขึ้น 🚀

เขียนโดย

อ่านต่อ