จัดการการเปลี่ยนแปลงการกำหนดค่า

การกำหนดค่าอุปกรณ์บางอย่างอาจเปลี่ยนแปลงขณะที่แอปกำลังทำงานอยู่ ซึ่งรวมถึงแต่ไม่จำกัดเพียงสิ่งต่อไปนี้

  • ขนาดการแสดงผลของแอป
  • การวางแนวหน้าจอ
  • ขนาดและน้ำหนักแบบอักษร
  • ภาษา
  • โหมดมืดเทียบกับโหมดสว่าง
  • ความพร้อมใช้งานของแป้นพิมพ์

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

หากแอปพลิเคชันของคุณขึ้นอยู่กับการรีสตาร์ททั้งหมดเพื่อโหลดทรัพยากรใหม่สำหรับการเปลี่ยนแปลงเหล่านี้ ตอนนี้คุณต้องเลือกใช้ลักษณะการทำงานเดิมอย่างชัดเจนโดยใช้แอตทริบิวต์ 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 เมื่อใดก็ตามที่ออบเจ็กต์นี้เปลี่ยนแปลง ฟังก์ชัน Composable ที่อ่านจาก 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

แหล่งข้อมูลเพิ่มเติม

ดูข้อมูลเพิ่มเติมเกี่ยวกับการจัดการการเปลี่ยนแปลงการกำหนดค่าได้จากแหล่งข้อมูลเพิ่มเติมต่อไปนี้

เอกสารประกอบ

เนื้อหา View