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

ยกระดับการเล่นสื่อ: เจาะลึก 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: การแคชด้วยสื่อที่โหลดล่วงหน้า

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

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

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

เขียนโดย

อ่านต่อ