การกำหนดค่าอุปกรณ์บางอย่างอาจเปลี่ยนแปลงขณะที่แอปกำลังทำงานอยู่ ซึ่งรวมถึงแต่ไม่จำกัดเพียงสิ่งต่อไปนี้
- ขนาดการแสดงผลของแอป
- การวางแนวหน้าจอ
- ขนาดและน้ำหนักแบบอักษร
- ภาษา
- โหมดมืดเทียบกับโหมดสว่าง
- ความพร้อมใช้งานของแป้นพิมพ์
การเปลี่ยนแปลงการกำหนดค่าส่วนใหญ่เกิดขึ้นเนื่องจากการโต้ตอบของผู้ใช้ เช่น การหมุนหรือพับอุปกรณ์จะเปลี่ยนพื้นที่หน้าจอที่แอปใช้ได้ ในทำนองเดียวกัน การเปลี่ยนการตั้งค่าอุปกรณ์ เช่น ขนาดแบบอักษร ภาษา หรือธีมที่ต้องการ จะเปลี่ยนค่าที่เกี่ยวข้องในออบเจ็กต์ Configuration
โดยปกติแล้วพารามิเตอร์เหล่านี้ต้องมีการเปลี่ยนแปลง UI ของแอปพลิเคชันมากพอที่แพลตฟอร์ม Android จะมีกลไกที่สร้างขึ้นเพื่อวัตถุประสงค์เฉพาะสำหรับการเปลี่ยนแปลงดังกล่าว
กลไกนี้คือ การสร้าง Activity ขึ้นใหม่
การสร้าง Activity ขึ้นใหม่
ระบบจะสร้าง Activity ขึ้นใหม่เมื่อมีการเปลี่ยนแปลงการกำหนดค่า โดยระบบจะเรียก onDestroy และทำลายอินสแตนซ์ Activity
ที่มีอยู่ จากนั้นจะสร้างอินสแตนซ์ใหม่โดยใช้ onCreate และอินสแตนซ์ใหม่
Activityนี้จะเริ่มต้นด้วยการกำหนดค่าใหม่ที่อัปเดตแล้ว ซึ่งหมายความว่าระบบจะสร้าง UI ขึ้นใหม่ด้วยการกำหนดค่าใหม่ด้วย
โดยปกติแล้ว Activity จะทำหน้าที่เป็นโฮสต์สำหรับ Composable เมื่อมีการสร้าง Activity ขึ้นใหม่ Compose จะสร้าง UI ขึ้นใหม่ด้วยค่าการกำหนดค่าใหม่ด้วย
ลักษณะการทำงานของการสร้างขึ้นใหม่จะช่วยให้แอปพลิเคชันปรับให้เข้ากับการกำหนดค่าใหม่ได้โดยการโหลดแอปพลิเคชันซ้ำโดยอัตโนมัติด้วยทรัพยากรทางเลือกที่ตรงกับการกำหนดค่าอุปกรณ์ใหม่
ตัวอย่างการสร้างขึ้นใหม่
ลองพิจารณา Composable ที่แสดงชื่อแบบคงที่โดยใช้ทรัพยากรสตริง
// In the res/values/strings.xml file // <string name="compose">Jetpack Compose</string> // In your Compose code Text( text = stringResource(R.string.compose) )
เมื่อมีการสร้าง Activity ขึ้น Composable Text จะอ่านการกำหนดค่าปัจจุบัน (เช่น ภาษา) และแสดงทรัพยากรสตริงที่เหมาะสม
หากภาษาเปลี่ยนไป ระบบจะสร้าง Activity ขึ้นใหม่ เมื่อเกิดเหตุการณ์นี้ Compose จะสร้าง UI ขึ้นใหม่ เนื่องจาก stringResource อ่านจากการกำหนดค่าปัจจุบัน ชื่อจึงอัปเดตเป็นค่าที่แปลเป็นภาษาท้องถิ่นที่ถูกต้องโดยอัตโนมัติ
การสร้างขึ้นใหม่ยังล้างสถานะที่เก็บไว้เป็นช่องใน Activity ด้วย
หากต้องการเก็บรักษาสถานะ UI ไว้เมื่อมีการเปลี่ยนแปลงการกำหนดค่า ให้ใช้รูปแบบการจัดการสถานะที่แนะนำ ใช้ ViewModel สำหรับข้อมูลและตรรกะทางธุรกิจ และใช้ rememberSaveable สำหรับสถานะระดับ UI กลไกเหล่านี้จะช่วยให้สถานะยังคงอยู่เมื่อมีการสร้าง Activity ขึ้นใหม่ ขณะที่ UI อัปเดตเพื่อแสดงการกำหนดค่าใหม่
ดูข้อมูลเพิ่มเติมเกี่ยวกับการบันทึกสถานะใน Compose ได้ที่ หัวข้อบันทึกสถานะ UI ใน Compose
ความคาดหวังของผู้ใช้
ผู้ใช้แอปคาดหวังให้ระบบเก็บรักษาสถานะไว้ หากผู้ใช้กำลังกรอกแบบฟอร์มและเปิดแอปอื่นในโหมดหลายหน้าต่างเพื่ออ้างอิงข้อมูล การที่ผู้ใช้กลับมาที่แบบฟอร์มที่ล้างข้อมูลแล้วหรือกลับไปที่ส่วนอื่นของแอปทั้งหมดจะเป็นประสบการณ์การใช้งานที่ไม่ดี ในฐานะนักพัฒนาแอป คุณต้องมอบประสบการณ์การใช้งานที่สอดคล้องกันเมื่อมีการเปลี่ยนแปลงการกำหนดค่าและการสร้าง Activity ขึ้นใหม่
หากต้องการตรวจสอบว่าระบบเก็บรักษาสถานะไว้ในแอปพลิเคชันหรือไม่ คุณสามารถดำเนินการที่ทำให้เกิดการเปลี่ยนแปลงการกำหนดค่าทั้งขณะที่แอปอยู่ในเบื้องหน้าและขณะที่แอปอยู่ในเบื้องหลัง การดำเนินการดังกล่าว ได้แก่
- การหมุนอุปกรณ์
- การเข้าสู่โหมดหลายหน้าต่าง
- การปรับขนาดแอปพลิเคชันขณะอยู่ในโหมดหลายหน้าต่างหรือหน้าต่างแบบอิสระ
- การพับอุปกรณ์พับได้ที่มีจอแสดงผลหลายจอ
- การเปลี่ยนธีมของระบบ เช่น โหมดมืดเทียบกับโหมดสว่าง
- การเปลี่ยนขนาดแบบอักษร
- การเปลี่ยนภาษาของระบบหรือแอป
- การเชื่อมต่อหรือยกเลิกการเชื่อมต่อแป้นพิมพ์ฮาร์ดแวร์
- การเชื่อมต่อหรือยกเลิกการเชื่อมต่อแท่นวาง
คุณสามารถใช้แนวทางต่างๆ เพื่อเก็บรักษาสถานะที่เกี่ยวข้องไว้เมื่อมีการสร้าง Activity ขึ้นใหม่ โดยแนวทางที่ใช้จะขึ้นอยู่กับประเภทสถานะที่ต้องการเก็บรักษา
- การคงอยู่ของข้อมูลในเครื่อง เพื่อจัดการการสิ้นสุดการประมวลผลสำหรับข้อมูลที่ซับซ้อนหรือมีขนาดใหญ่
พื้นที่เก็บข้อมูลในเครื่องแบบถาวรรวมถึงฐานข้อมูลหรือ
DataStore. - ออบเจ็กต์ที่เก็บรักษาไว้ เช่น
ViewModelอินสแตนซ์ เพื่อจัดการ สถานะที่เกี่ยวข้องกับ UI ในหน่วยความจำขณะที่ผู้ใช้ใช้งานแอปอยู่ rememberSaveableเพื่อเก็บรักษาสถานะ UI ชั่วคราวไว้เมื่อมีการเปลี่ยนแปลงการกำหนดค่าและการสิ้นสุดการประมวลผลที่ระบบเริ่มขึ้น วิธีนี้เหมาะสำหรับสถานะที่ขึ้นอยู่กับข้อมูลจากผู้ใช้ ตำแหน่งการเลื่อน หรือการนำทาง แต่ไม่ได้อยู่ในViewModel
หากต้องการอ่านข้อมูลโดยละเอียดเกี่ยวกับ API สำหรับแต่ละรายการ และเวลาที่ควรใช้แต่ละรายการ โปรดดูหัวข้อบันทึกสถานะ UI
จำกัดการสร้าง Activity ขึ้นใหม่
คุณสามารถป้องกันการสร้าง Activity ขึ้นใหม่โดยอัตโนมัติสำหรับการเปลี่ยนแปลงการกำหนดค่าบางอย่างได้ ในแอปที่ใช้ Compose เท่านั้นในปัจจุบัน ระบบจะสร้าง UI ขึ้นใหม่ไม่ว่าในกรณีใดก็ตาม แต่เราขอแนะนำให้จัดการการเปลี่ยนแปลงการกำหนดค่าโดยตรง
โดยค่าเริ่มต้น การเปลี่ยนแปลงการกำหนดค่าจะบังคับให้ระบบทำลายและสร้าง Activity ขึ้นใหม่ ซึ่งรวมถึง UI และออบเจ็กต์ใดๆ ที่ได้มาจาก Activity หากคุณประกาศว่า Activity ของคุณจัดการการเปลี่ยนแปลงการกำหนดค่าด้วยตัวเอง ระบบจะป้องกันไม่ให้เกิดเหตุการณ์นี้ แต่ระบบจะอัปเดตเฉพาะออบเจ็กต์ Configuration และ Compose จะสร้าง UI ขึ้นใหม่ด้วยค่าใหม่
การจัดการการเปลี่ยนแปลงการกำหนดค่าโดยตรงใน Compose มีประโยชน์หลายประการ ดังนี้
- ประสิทธิภาพที่ดีขึ้น: การสร้าง UI ขึ้นใหม่ใช้ทรัพยากรน้อยกว่าวงจรการสร้าง Activity ขึ้นใหม่ทั้งหมด โดยเฉพาะอย่างยิ่งสำหรับการเปลี่ยนแปลงเล็กน้อย
- ภาพเคลื่อนไหวที่ราบรื่น: การหลีกเลี่ยงการรีสตาร์ท Activity ช่วยให้คุณเรียกใช้ภาพเคลื่อนไหวต่อเนื่องเมื่อมีการเปลี่ยนแปลงการกำหนดค่า เช่น การเปลี่ยนเลย์เอาต์อย่างราบรื่นระหว่างการหมุนอุปกรณ์
- การเก็บรักษาสถานะ: การเก็บรักษาอินสแตนซ์ Activity ช่วยลดความเสี่ยงที่สถานะ UI ชั่วคราวจะสูญหายระหว่างเหตุการณ์ต่างๆ เช่น การหมุนหน้าจอ โปรดทราบว่าคุณยังคงต้องจัดการการเก็บรักษาสถานะไว้เมื่อมีการสิ้นสุดกระบวนการที่ระบบเริ่มขึ้น
หากต้องการปิดใช้การสร้าง Activity ขึ้นใหม่สำหรับการเปลี่ยนแปลงการกำหนดค่าบางอย่าง
ให้เพิ่มประเภทการกำหนดค่าลงใน android:configChanges ในรายการ
<activity> ในไฟล์ AndroidManifest.xml ค่าที่เป็นไปได้
จะปรากฏในเอกสารประกอบสำหรับแอตทริบิวต์ android:configChanges
โค้ด Manifest ต่อไปนี้จะปิดใช้ Activity การสร้างขึ้นใหม่สำหรับ MyActivity เมื่อ
การวางแนวหน้าจอและความพร้อมใช้งานของแป้นพิมพ์เปลี่ยนไป
<activity
android:name=".MyActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:label="@string/app_name">
Android 17
ตั้งแต่ Android 17 (API ระดับ 37) เป็นต้นไป ระบบจะไม่รีสตาร์ท Activity โดยค่าเริ่มต้นสำหรับการเปลี่ยนแปลงการกำหนดค่าหลายอย่างที่โดยปกติแล้วไม่จำเป็นต้องสร้าง UI ขึ้นใหม่ทั้งหมด
แต่ Activity จะยังคงทำงานอยู่และรับการอัปเดตผ่านการเรียกกลับ
onConfigurationChanged()
การเปลี่ยนแปลงการกำหนดค่าที่เฉพาะเจาะจง ได้แก่
CONFIG_KEYBOARDCONFIG_KEYBOARD_HIDDENCONFIG_NAVIGATIONCONFIG_TOUCHSCREENCONFIG_COLOR_MODECONFIG_UI_MODE(เฉพาะเมื่อโหมด UI เปลี่ยนเป็นUI_MODE_TYPE_DESKหรือจากUI_MODE_TYPE_DESKเป็นประเภทอื่น)
หากแอปพลิเคชันของคุณต้องรีสตาร์ททั้งหมดเพื่อโหลดทรัพยากรสำหรับการเปลี่ยนแปลงเหล่านี้
คุณต้องเลือกใช้ลักษณะการทำงานเดิมอย่างชัดเจนโดยใช้
android:recreateOnConfigChanges ในไฟล์ Manifest
แอตทริบิวต์นี้ช่วยให้คุณระบุได้ว่าการเปลี่ยนแปลงการกำหนดค่าใดที่ควรทริกเกอร์การหยุด ทำลาย และสร้างวงจร Activity ขึ้นใหม่ทั้งหมด เช่น
<activity
android:name=".MyActivity"
android:recreateOnConfigChanges="keyboard|keyboardHidden|navigation|colorMode|touchscreen|...">
...
</activity>
ตอบสนองต่อการเปลี่ยนแปลงการกำหนดค่า
Jetpack Compose ช่วยให้แอปของคุณตอบสนองต่อการเปลี่ยนแปลงการกำหนดค่าได้ง่ายขึ้น
อย่างไรก็ตาม หากคุณปิดใช้การสร้าง Activity ขึ้นใหม่สำหรับการเปลี่ยนแปลงการกำหนดค่าทั้งหมดที่ทำได้ แอปของคุณก็ยังคงต้องจัดการการเปลี่ยนแปลงการกำหนดค่าอย่างถูกต้อง
ออบเจ็กต์ Configuration มีอยู่ในลำดับชั้น UI ของ Compose พร้อมด้วย
Composition Local LocalConfiguration เมื่อใดก็ตามที่ออบเจ็กต์นี้เปลี่ยนแปลง ฟังก์ชันที่ประกอบกันได้ซึ่งอ่านจาก LocalConfiguration.current จะสร้างขึ้นใหม่ ดูข้อมูลเกี่ยวกับวิธีการทำงานของ Composition Local ได้ที่หัวข้อข้อมูลที่มีขอบเขตเฉพาะที่ด้วย CompositionLocal
ตัวอย่าง
ในตัวอย่างต่อไปนี้ Composable จะแสดงวันที่ในรูปแบบที่เฉพาะเจาะจง
Composable จะตอบสนองต่อการเปลี่ยนแปลงการกำหนดค่าภาษาของระบบโดยการเรียก
ConfigurationCompat.getLocales ด้วย LocalConfiguration.current
@Composable
fun DateText(year: Int, dayOfYear: Int) {
val dateTimeFormatter = DateTimeFormatter.ofPattern(
"MMM dd",
ConfigurationCompat.getLocales(LocalConfiguration.current)[0]
)
Text(
dateTimeFormatter.format(LocalDate.ofYearDay(year, dayOfYear))
)
}
หากต้องการหลีกเลี่ยงการสร้าง Activity ขึ้นใหม่เมื่อภาษาเปลี่ยนไป Activity ที่โฮสต์โค้ด Compose ต้องเลือกไม่รับการเปลี่ยนแปลงการกำหนดค่าภาษา โดยตั้งค่า android:configChanges เป็น locale|layoutDirection
การเปลี่ยนแปลงการกำหนดค่า: แนวคิดหลักและแนวทางปฏิบัติแนะนำ
แนวคิดหลักที่ควรทราบเมื่อทำงานเกี่ยวกับการเปลี่ยนแปลงการกำหนดค่ามีดังนี้
- การกำหนดค่า: การกำหนดค่าอุปกรณ์จะกำหนดวิธีที่ UI แสดงต่อผู้ใช้ เช่น ขนาดการแสดงผลของแอป ภาษา หรือธีมของระบบ ใน Compose คุณสามารถเข้าถึงค่าการกำหนดค่าได้โดยใช้
LocalConfiguration - การเปลี่ยนแปลงการกำหนดค่า: การกำหนดค่าจะเปลี่ยนแปลงผ่านการโต้ตอบของผู้ใช้ เช่น ผู้ใช้อาจเปลี่ยนการตั้งค่าอุปกรณ์หรือวิธีโต้ตอบกับอุปกรณ์ทางกายภาพ ไม่มีวิธีป้องกันการเปลี่ยนแปลงการกำหนดค่า
- การสร้าง
Activityขึ้นใหม่: โดยค่าเริ่มต้น การเปลี่ยนแปลงการกำหนดค่าจะส่งผลให้มีการสร้างActivityขึ้นใหม่ ซึ่งเป็นกลไกในตัวเพื่อเริ่มต้นสถานะแอปใหม่สำหรับการกำหนดค่าใหม่ - การทำลาย
Activity: การสร้างActivityขึ้นใหม่จะทำให้ระบบทำลายอินสแตนซ์Activityเก่าและสร้างอินสแตนซ์ใหม่ขึ้นมาแทน อินสแตนซ์เก่าจะล้าสมัยแล้ว หลีกเลี่ยงการเก็บรักษาการอ้างอิงออบเจ็กต์ที่มีขอบเขตตามวงจรการทำงานนอกเหนือขอบเขตที่ตั้งใจไว้ - สถานะ: สถานะในอินสแตนซ์
Activityเก่าจะไม่มีอยู่ในอินสแตนซ์Activityใหม่ เนื่องจากเป็นอินสแตนซ์ออบเจ็กต์ 2 รายการที่แตกต่างกัน ให้ใช้ API ที่แนะนำเพื่อเก็บรักษาสถานะของแอปและผู้ใช้ตามที่อธิบายไว้ในหัวข้อ บันทึกสถานะ UI แทนที่จะผูกสถานะไว้กับ Activity - การเลือกไม่รับ: การเลือกไม่รับการสร้าง Activity ขึ้นใหม่สำหรับการเปลี่ยนแปลงการกำหนดค่าประเภทหนึ่งกำหนดให้แอปของคุณต้องอัปเดตอย่างเหมาะสมเพื่อตอบสนองต่อการกำหนดค่าใหม่
โปรดปฏิบัติตามแนวทางปฏิบัติแนะนำต่อไปนี้เพื่อมอบประสบการณ์การใช้งานที่ดี
- เตรียมพร้อมสำหรับการเปลี่ยนแปลงการกำหนดค่าบ่อยครั้ง: อย่าคิดว่าการเปลี่ยนแปลงการกำหนดค่าเกิดขึ้นไม่บ่อยนักหรือไม่มีทางเกิดขึ้น ไม่ว่าจะเป็นระดับ API รูปแบบของอุปกรณ์ หรือชุดเครื่องมือ UI เมื่อผู้ใช้ทำให้เกิดการเปลี่ยนแปลงการกำหนดค่า ผู้ใช้คาดหวังให้แอปอัปเดตและทำงานต่อไปอย่างถูกต้องด้วยการกำหนดค่าใหม่
- เก็บรักษาสถานะ: อย่าให้สถานะของผู้ใช้สูญหายเมื่อมีการสร้าง
Activityขึ้นใหม่ เก็บบันทึกสถานะตามที่อธิบายไว้ใน บันทึกสถานะ UI โดยใช้ API เช่นViewModelและrememberSaveable - หลีกเลี่ยงการเลือกไม่รับเพื่อแก้ไขปัญหาอย่างรวดเร็ว: อย่าเลือกไม่รับการสร้าง
Activityขึ้นใหม่เพื่อเป็นทางลัดในการหลีกเลี่ยงการสูญเสียสถานะ การเลือกไม่รับการสร้าง Activity ขึ้นใหม่กำหนดให้คุณต้องทำตามสัญญาในการจัดการการเปลี่ยนแปลง และคุณอาจยังคงสูญเสียสถานะเนื่องจากการสร้างActivityขึ้นใหม่จากการเปลี่ยนแปลงการกำหนดค่าอื่นๆ การสิ้นสุดกระบวนการ หรือการปิดแอป การปิดใช้การสร้างActivityขึ้นใหม่ทั้งหมดเป็นไปไม่ได้ เก็บบันทึกสถานะตามที่อธิบายไว้ในหัวข้อ บันทึกสถานะ UI - อย่าหลีกเลี่ยงการเปลี่ยนแปลงการกำหนดค่า: อย่าจำกัดการวางแนว
อัตราส่วนกว้างยาว หรือการปรับขนาดเพื่อหลีกเลี่ยงการเปลี่ยนแปลงการกำหนดค่าและการสร้าง
Activityขึ้นใหม่ ซึ่งจะส่งผลเสียต่อผู้ใช้ที่ต้องการใช้แอปของคุณในแบบที่ต้องการ
จัดการการเปลี่ยนแปลงการกำหนดค่าตามขนาด
การเปลี่ยนแปลงการกำหนดค่าตามขนาดอาจเกิดขึ้นได้ทุกเมื่อ และมีแนวโน้มที่จะเกิดขึ้นมากขึ้น เมื่อแอปของคุณทำงานในอุปกรณ์หน้าจอขนาดใหญ่ที่ผู้ใช้สามารถเข้าสู่ โหมดหลายหน้าต่างได้ ผู้ใช้คาดหวังให้แอปของคุณทำงานได้ดีในสภาพแวดล้อมดังกล่าว
การเปลี่ยนแปลงขนาดมี 2 ประเภททั่วไป ได้แก่ การเปลี่ยนแปลงอย่างมีนัยสำคัญและการเปลี่ยนแปลงเล็กน้อย การเปลี่ยนแปลงขนาด อย่างมีนัยสำคัญ คือการเปลี่ยนแปลงที่ทรัพยากรทางเลือกชุดอื่นมีผลกับการกำหนดค่าใหม่เนื่องจากขนาดหน้าจอแตกต่างกัน เช่น ความกว้าง ความสูง หรือความกว้างที่เล็กที่สุด ทรัพยากรเหล่านี้รวมถึงทรัพยากรที่แอปกำหนดขึ้นเองและทรัพยากรจากไลบรารีใดๆ ของแอป
จำกัดการสร้าง Activity ขึ้นใหม่สำหรับการเปลี่ยนแปลงการกำหนดค่าตามขนาด
เมื่อคุณปิดใช้การสร้าง Activity ขึ้นใหม่สำหรับการเปลี่ยนแปลงการกำหนดค่าตามขนาด ระบบจะไม่สร้าง Activity ขึ้นใหม่ แต่จะรับการเรียก
Activity.onConfigurationChanged Composable ใดๆ ที่อ่าน LocalConfiguration.current จะสร้างขึ้นใหม่โดยอัตโนมัติเพื่อแสดงขนาดใหม่
ระบบจะปิดใช้การสร้าง Activity ขึ้นใหม่สำหรับการเปลี่ยนแปลงการกำหนดค่าตามขนาดเมื่อ
คุณมี
android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout"
ในไฟล์ Manifest
แหล่งข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับการจัดการการเปลี่ยนแปลงการกำหนดค่าได้จากแหล่งข้อมูลเพิ่มเติมต่อไปนี้