Media3 เปิดตัวการเพิ่มประสิทธิภาพใหม่ การปรับปรุงลักษณะการทำงาน และการปรับปรุงสถาปัตยกรรมในไลบรารีต่างๆ แม้ว่าการเปลี่ยนแปลงเหล่านี้จะได้รับการทดสอบและยืนยันอย่างละเอียดก่อนเผยแพร่ แต่ Media3 ก็มีโครงสร้างพื้นฐานแฟล็กฟีเจอร์แบบรวมศูนย์ (androidx.media3.common.Flags) ที่เน้นโหมด Canary เพื่อให้แอปพลิเคชันควบคุมวิธีและเวลาที่จะนำลักษณะการทำงานใหม่ๆ มาใช้
หน้านี้อธิบายวิธีการทำงานของโหมด Canary และแฟล็กฟีเจอร์ รวมถึงวิธีใช้ในแอปพลิเคชันเพื่อลดความเสี่ยงในการอัปเกรดในรุ่นต่างๆ เรียกใช้การเปิดตัวที่มีการควบคุม และกำหนดค่าการย้อนกลับฉุกเฉิน
ภาพรวม
โหมด Canary จะจัดกลุ่มการปรับปรุงไลบรารีที่ได้รับการยืนยันและเปิดตัวใหม่ไว้ภายใต้ปุ่มเปิด/ปิดส่วนกลางแบบรวม ดังนี้
- เปิดใช้โดยค่าเริ่มต้น: ใน Media3 รุ่นมาตรฐาน โหมด Canary จะเปิดใช้โดยค่าเริ่มต้น (
true) ซึ่งช่วยให้แอปของคุณได้รับประโยชน์จากการปรับปรุงประสิทธิภาพ การเพิ่มประสิทธิภาพ และความสามารถใหม่ๆ ที่ปลอดภัยโดยอัตโนมัติ - ความสามารถในการเลือกไม่ใช้และการย้อนกลับ: แอปพลิเคชันสามารถปิดใช้โหมด Canary ทั่วโลกหรือลบล้างแฟล็กฟีเจอร์ที่เฉพาะเจาะจงทีละรายการขณะรันไทม์ได้
- การเดินสายที่ซับซ้อนเป็นศูนย์: ระบบจะจัดการแฟล็กผ่านคลาส
Flagsส่วนกลางในโมดูลcommonซึ่งช่วยลดความจำเป็นในการใช้ Setter หรือออบเจ็กต์การกำหนดค่าที่กำหนดเองในคอมโพเนนต์ต่างๆ
เหตุใดจึงควรใช้แฟล็กในแอป
แม้ว่าโหมด Canary จะทำงานอยู่โดยค่าเริ่มต้น แต่การผสานรวม Flags กับการกำหนดค่าหรือเฟรมเวิร์กการทดสอบของแอปก็มีประโยชน์หลายประการ ดังนี้
1. การลดความเสี่ยงในการอัปเกรดเวอร์ชัน
การอัปเกรดไลบรารีเวอร์ชันหลักหรือเวอร์ชันย่อยในเวอร์ชันที่ใช้งานจริงอาจทำให้เกิดการโต้ตอบที่ไม่คาดคิดในอุปกรณ์ OEM บางรุ่นหรือไปป์ไลน์สื่อที่กำหนดเอง เมื่ออัปเดต Media3 คุณสามารถใช้โหมด Canary และการกำหนดค่าระยะไกลเพื่อให้ขั้นตอนการอัปเกรดปลอดภัยยิ่งขึ้นในรุ่นต่างๆ ดังนี้
- จัดส่งการอัปเดตโดยปิดใช้โหมด Canary: การเผยแพร่ Media3 เวอร์ชันใหม่โดยปิดใช้โหมด Canary จะคงชุดฟีเจอร์ของเวอร์ชันก่อนหน้าไว้ (โดยเปิดใช้ Canary) ซึ่งช่วยให้คุณยืนยันความเสถียรของไลบรารีพื้นฐานและการแก้ไขข้อบกพร่องทั่วไปในเวอร์ชันที่ใช้งานจริงได้ก่อนที่จะนำลักษณะการทำงานใหม่มาใช้
- เปิดใช้โหมด Canary แบบค่อยเป็นค่อยไป: ใช้การกำหนดค่าระยะไกลเพื่อเปิดใช้โหมด Canary เป็นระยะๆ ในกลุ่มประชากรตามรุ่นของผู้ใช้ (เช่น 5% → 25% → 100%) หรือทำการทดสอบ A/B เพื่อวัดผลกระทบของเมตริก
- ย้อนกลับหากจำเป็น: หากเกิดการถดถอยในอุปกรณ์บางเครื่อง ให้ปิดใช้โหมด Canary หรือรหัส Flag ที่เฉพาะเจาะจงจากระยะไกลโดยไม่ต้องเผยแพร่แอปฉุกเฉิน
- ใช้เป็นค่าเริ่มต้น: เมื่อยืนยันแล้ว ให้เปิดใช้โหมด Canary ไว้โดยค่าเริ่มต้นจนกว่าจะอัปเกรดเวอร์ชันถัดไป ซึ่งฟีเจอร์ Canary ที่ยืนยันก่อนหน้านี้จะกลายเป็นฟีเจอร์ถาวร
Kotlin
// Enable or disable Canary mode globally (defaults to true). Flags.setCanaryModeEnabled(false)
Java
// Enable or disable Canary mode globally (defaults to true). Flags.setCanaryModeEnabled(false);
2. การเปิดตัวแบบทีละขั้นที่มีการควบคุมและการทดสอบ A/B
แทนที่จะแสดงลักษณะการทำงานใหม่ของไลบรารีแก่ผู้ใช้ 100% พร้อมกัน คุณสามารถเชื่อมต่อ Flags กับการกำหนดค่าระยะไกลหรือระบบการทดสอบได้
คุณสามารถเปิดใช้โหมด Canary เป็นระยะ (เช่น ผู้ใช้ 5% → 25% → 100%) หรือทำการทดสอบ A/B เพื่อวัดผลกระทบของการเพิ่มประสิทธิภาพใหม่ๆ ต่อเมตริกการเล่นหลัก เช่น เวลาในการตอบสนองเมื่อเริ่มต้น อัตราการบัฟเฟอร์ซ้ำ และการเล่นไม่สำเร็จ
3. คิลสวิตช์ระยะไกลและการย้อนกลับอย่างรวดเร็ว
หากเกิดการถดถอยในเวอร์ชันที่ใช้งานจริงในอุปกรณ์รุ่นหรือระบบปฏิบัติการเวอร์ชันใดเวอร์ชันหนึ่ง คุณสามารถปิดใช้โหมด Canary (หรือรหัสแฟล็กที่รับผิดชอบ) จากระยะไกลได้โดยใช้การกำหนดค่าฝั่งเซิร์ฟเวอร์ ซึ่งจะเปลี่ยนกลับไลบรารีเป็นลักษณะการทำงานสำรองเดิมที่เสถียรสำหรับผู้ใช้ที่ได้รับผลกระทบทันที โดยไม่จำเป็นต้องใช้การแก้ไขด่วนสำหรับแอปฉุกเฉินหรือการเผยแพร่ไบนารี
การกำหนดค่าโหมด Canary และแฟล็ก
Flags API มีเมธอดในการควบคุมโหมด Canary ทั่วโลกและการลบล้างแฟล็กแต่ละรายการ
โหมด Canary ทั่วโลก
วิธีเปิดหรือปิดใช้การเพิ่มประสิทธิภาพทั้งหมดที่ครอบคลุมโดยโหมด Canary
Kotlin
// Enable or disable Canary mode globally (defaults to true). Flags.setCanaryModeEnabled(false)
Java
// Enable or disable Canary mode globally (defaults to true). Flags.setCanaryModeEnabled(false);
การลบล้างแฟล็กแต่ละรายการ
นอกจากนี้ คุณยังเปิดหรือปิดใช้แฟล็กที่เฉพาะเจาะจงอย่างชัดแจ้งได้โดยไม่ขึ้นอยู่กับการตั้งค่าโหมด Canary ทั่วโลก ดังนี้
Kotlin
// Explicitly enable an experimental flag. Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) // Explicitly disable a flag. Flags.disableFlag(Flags.FLAG_DYNAMIC_SCHEDULING)
Java
// Explicitly enable an experimental flag. Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION); // Explicitly disable a flag. Flags.disableFlag(Flags.FLAG_DYNAMIC_SCHEDULING);
การลบล้างที่ชัดแจ้งจะมีผลเหนือกฎเริ่มต้นของโหมด Canary ทั่วโลกเสมอ
กำลังตรวจสอบสถานะการแจ้งว่าไม่เหมาะสม
หากต้องการตรวจสอบว่าโหมด Canary หรือแฟล็กที่เฉพาะเจาะจงทำงานอยู่ในโค้ดหรือไม่ ให้ทำดังนี้
Kotlin
// Query whether Canary mode is active globally. val isCanaryActive = Flags.isCanaryModeEnabled() // Query whether a specific flag is active. val isFeatureActive = Flags.isEnabled(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION)
Java
// Query whether Canary mode is active globally. boolean isCanaryActive = Flags.isCanaryModeEnabled(); // Query whether a specific flag is active. boolean isFeatureActive = Flags.isEnabled(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION);
ลำดับการแก้ไขปัญหาการแจ้งว่าไม่เหมาะสม
เมื่อ Media3 ตรวจสอบว่ามีการเปิดใช้ฟีเจอร์ขณะรันไทม์หรือไม่ ระบบจะแก้ไขสถานะตามลำดับต่อไปนี้
- การลบล้างรันไทม์ที่ชัดเจน: หากมีการเรียกใช้
enableFlagหรือdisableFlagสำหรับรหัสแฟล็ก ระบบจะแสดงผลค่าการลบล้างนั้น - สถานะไลบรารีแบบคงที่: หากแฟล็กถูกปิดใช้แบบคงที่ (เช่น ฟีเจอร์ที่อยู่ระหว่างการพัฒนาในช่วงแรกซึ่งยังไม่พร้อมสำหรับโหมด Canary) หรือเปิดใช้แบบคงที่ (ฟีเจอร์ที่จบการศึกษาจากโหมด Canary โดยยังคงมีการสำรองข้อมูลการเลือกไม่ใช้ชั่วคราว) ระบบจะแสดงผลค่าแบบคงที่นั้น
- สถานะโหมด Canary: มิฉะนั้น แฟล็กจะเป็นไปตามการตั้งค่าโหมด Canary ทั่วโลก (เปิดใช้หากโหมด Canary เป็น
trueและปิดใช้หากเป็นfalse)
ข้อกำหนดในการเริ่มต้นใช้งาน
กำหนดค่าแฟล็กก่อนสร้างอินสแตนซ์คอมโพเนนต์ Media3 (เช่น ExoPlayer, Transformer หรือ MediaSession) ดังนี้
- การตั้งค่าตั้งแต่เนิ่นๆ: กำหนดค่า
Flagsระหว่างการเริ่มต้นแอปพลิเคชัน (เช่น ภายในApplication.onCreate) หรือก่อนเริ่มต้นเลเยอร์สื่อของแอป - ความปลอดภัยของเทรด: คอมโพเนนต์ Media3 จะอ่านแฟล็กระหว่างการสร้างอินสแตนซ์และเผยแพร่ค่าเหล่านั้นไปยังเทรดการเล่นและการประมวลผลภายใน ตรวจสอบว่าการกำหนดค่าแฟล็กเกิดขึ้นก่อนสร้างคอมโพเนนต์ Media3 ระบบไม่รองรับการแก้ไขแฟล็กขณะที่เพลเยอร์หรือ Transformer กำลังทำงานอยู่
การผสานรวมกับการกำหนดค่าระยะไกล
สถาปัตยกรรมที่แนะนำคือการแสดงพารามิเตอร์ 3 รายการในแพลตฟอร์มการกำหนดค่าระยะไกล ดังนี้
media3_canary_mode_enabled(บูลีน): การเปิด/ปิดส่วนกลางสำหรับโหมด Canary (ค่าเริ่มต้นคือtrue)media3_force_enable_flags(รายการจำนวนเต็ม): รหัสแฟล็กที่เฉพาะเจาะจงเพื่อบังคับให้เปิดใช้สำหรับการทดลองที่กำหนดเป้าหมายmedia3_force_disable_flags(รายการจำนวนเต็ม): รหัสแฟล็กที่เฉพาะเจาะจงเพื่อบังคับปิดใช้หากพบปัญหา
ใช้ค่าเหล่านี้ระหว่างการเริ่มต้นก่อนสร้างอินสแตนซ์โปรแกรมเล่น
Kotlin
fun initializeMedia3Flags( canaryModeEnabled: Boolean, forceEnabledFlags: List<Int>, forceDisabledFlags: List<Int>, ) { // 1. Set global Canary mode state. Flags.setCanaryModeEnabled(canaryModeEnabled) // 2. Apply explicit force-enable overrides. for (flagId in forceEnabledFlags) { Flags.enableFlag(flagId) } // 3. Apply explicit force-disable overrides (remote kill switch). for (flagId in forceDisabledFlags) { Flags.disableFlag(flagId) } }
Java
public static void initializeMedia3Flags( boolean canaryModeEnabled, List<Integer> forceEnabledFlags, List<Integer> forceDisabledFlags) { // 1. Set global Canary mode state. Flags.setCanaryModeEnabled(canaryModeEnabled); // 2. Apply explicit force-enable overrides. for (int flagId : forceEnabledFlags) { Flags.enableFlag(flagId); } // 3. Apply explicit force-disable overrides (remote kill switch). for (int flagId : forceDisabledFlags) { Flags.disableFlag(flagId); } }
การทดสอบด้วยแฟล็ก
เมื่อเขียน Unit Test หรือการทดสอบ Robolectric สำหรับเส้นทางโค้ดที่ได้รับผลกระทบจากแฟล็กฟีเจอร์ ให้ใช้ androidx.media3.test.utils.Media3FlagsRule (มีอยู่ในโมดูล media3-test-utils) เพื่อให้แน่ใจว่าการทดสอบจะไม่รบกวนสถานะคงที่ของกันและกัน
การล้างข้อมูลอัตโนมัติด้วย Media3FlagsRule
การเพิ่ม Media3FlagsRule จะช่วยให้มั่นใจได้ว่าการลบล้างแฟล็กและการแก้ไขโหมด Canary ทั้งหมดจะรีเซ็ตโดยอัตโนมัติหลังจากการทดสอบแต่ละครั้ง
Kotlin
class MyPlayerTest { @get:Rule val flagsRule = Media3FlagsRule(this) @Test fun playback_withFeatureFlagEnabled() { Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) // Run test with the flag enabled... } }
Java
public static class MyPlayerTest { @Rule public final Media3FlagsRule flagsRule = new Media3FlagsRule(this); @Test public void playback_withFeatureFlagEnabled() { Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION); // Run test with the flag enabled... } }
การทดสอบพารามิเตอร์
คุณสามารถรวมคำอธิบายประกอบ Media3FlagsRule กับ @BindFlag และ @BindCanaryMode เพื่อทำการทดสอบที่กำหนดพารามิเตอร์ในสถานะแฟล็กต่างๆ ได้ดังนี้
Kotlin
class MyParameterizedPlayerTest { @BindCanaryMode var canaryMode: Boolean = false @BindFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) var perStreamProgression: Boolean = false @get:Rule val flagsRule = Media3FlagsRule(this) @Test fun playback() { // Flags are automatically set for each test parameter combination. } }
Java
public static class MyParameterizedPlayerTest { @BindCanaryMode public boolean canaryMode; @BindFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) public boolean perStreamProgression; @Rule public final Media3FlagsRule flagsRule = new Media3FlagsRule(this); @Test public void playback() { // Flags are automatically set for each test parameter combination. } }
การวินิจฉัยและการบันทึก
Media3 มีเครื่องมือวินิจฉัยเพื่อยืนยันแฟล็กที่ใช้งานอยู่และสถานะโหมด Canary ระหว่างการเริ่มต้นการเล่นและที่รันไทม์
บันทึกการเริ่มต้น
เมื่ออินสแตนซ์ ExoPlayer เริ่มต้น ระบบจะพิมพ์สถานะ Canary ที่ใช้งานอยู่และการลบล้างที่ชัดเจนไปยัง logcat ควบคู่ไปกับเวอร์ชันไลบรารี ดังนี้
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON]
หากการลบล้างทำงานอยู่ ระบบจะแสดงเฉพาะค่าที่เบี่ยงเบนไปจากสถานะเริ่มต้น ดังนี้
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON, Overrides: enabled=[1], disabled=[3]]
การตรวจสอบแบบเป็นโปรแกรม
คุณสามารถดึงข้อมูลสตริงการวินิจฉัยที่จัดรูปแบบแล้วหรือรายการการลบล้างการค้นหาแบบเป็นโปรแกรมได้ (เช่น เพื่อรวมสถานะแฟล็กในรายงานข้อขัดข้องหรือข้อมูลวิเคราะห์ของแอป)
Kotlin
// Get formatted string representing active Canary state and overrides. val flagLogString = Flags.getLogString() // Query explicit override IDs if needed. val enabledFlags = Flags.getEnabledOverrides() val disabledFlags = Flags.getDisabledOverrides()
Java
// Get formatted string representing active Canary state and overrides. String flagLogString = Flags.getLogString(); // Query explicit override IDs if needed. int[] enabledFlags = Flags.getEnabledOverrides(); int[] disabledFlags = Flags.getDisabledOverrides();
วงจรของการแจ้งว่าไม่เหมาะสม
แฟล็กใน Media3 ออกแบบมาให้เป็นแบบชั่วคราว ดังนี้
- การพัฒนา: มีการเพิ่มการเพิ่มประสิทธิภาพหรือฟีเจอร์ใหม่หลังรหัสแฟล็กใน
Flags.java - โหมด Canary: เมื่อได้รับการยืนยันและพร้อมใช้งานทั่วไปแล้ว ฟีเจอร์จะทำงานภายใต้โหมด Canary ในทุกรุ่น
- การโปรโมตและการล้างข้อมูล: หลังจากระยะเวลาทดสอบที่พิสูจน์ความเสถียรในเวอร์ชันที่ใช้งานจริงแล้ว ฟีเจอร์จะได้รับการโปรโมตให้เปิดใช้ถาวรในไลบรารี และระบบจะนำค่าคงที่ของแฟล็ก เส้นทางโค้ดสำรอง และการตรวจสอบแบบมีเงื่อนไขออก
หากพบปัญหาเกี่ยวกับแฟล็กฟีเจอร์ โปรดส่งรายงานในเครื่องมือติดตามปัญหา AndroidX Media3 GitHub เพื่อให้ทีมแก้ไขปัญหาก่อนที่จะโปรโมตอย่างถาวร