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

ยกระดับการเล่นสื่อ: เจาะลึก 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): ระบบจะเรียกใช้ Callback นี้เมื่อคำขอโหลดล่วงหน้าเสร็จสมบูรณ์ตามที่กำหนดโดย TargetPreloadStatusControl
  • onError(ข้อผิดพลาด PreloadException): Callback นี้อาจมีประโยชน์สำหรับการแก้ไขข้อบกพร่องและการตรวจสอบ โดยจะเรียกใช้เมื่อการโหลดล่วงหน้าล้มเหลวและแสดงข้อยกเว้นที่เกี่ยวข้อง

คุณลงทะเบียน 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 callback เหล่านี้กับไปป์ไลน์ข้อมูลวิเคราะห์ได้ การส่งต่อเหตุการณ์เหล่านี้ไปยังเครื่องมือวิเคราะห์จะช่วยให้คุณตอบคำถามสำคัญๆ ได้ เช่น

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

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

นอกเหนือจากการแก้ไขข้อบกพร่อง: การใช้ onError สำหรับการเปลี่ยน UI กลับไปใช้เวอร์ชันสำรองอย่างราบรื่น

การโหลดล่วงหน้าที่ไม่สำเร็จเป็นตัวบ่งชี้ที่ชัดเจนว่าผู้ใช้จะได้รับเหตุการณ์บัฟเฟอร์ในเร็วๆ นี้ โดย onError Callback จะช่วยให้คุณตอบสนองได้อย่างรวดเร็ว คุณสามารถปรับ 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 สามารถเลือกแทร็กที่มีคุณภาพสูงสุดตามสภาพเครือข่ายปัจจุบันและสถานะของบัฟเฟอร์ในระหว่างการโหลดล่วงหน้าหรือการเล่น จากนั้นจะตัดสินใจอย่างชาญฉลาดเพื่อปกป้องเซสชันการเล่นที่ใช้งานอยู่และมอบประสบการณ์ที่ราบรื่น

preloadManagerBuilder.setBandwidthMeter(customBandwidthMeter)

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

  • LoadControl: คอมโพเนนต์นี้กำหนดนโยบายการบัฟเฟอร์ เช่น จำนวนข้อมูลที่จะบัฟเฟอร์ก่อนเริ่มเล่น และเวลาที่จะเริ่มหรือหยุดโหลดข้อมูลเพิ่มเติม การแชร์ LoadControl ช่วยให้มั่นใจได้ว่าการใช้หน่วยความจำของ Player และ 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)

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

preloadManagerBuilder.setRenderersFactory(customRenderersFactory)

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

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

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

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

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

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

โปรดติดตามข่าวสารและไปเพิ่มความเร็วในการเล่นวิดีโอกันเลย 🚀

เขียนโดย

อ่านต่อ