การกำหนดค่าอุปกรณ์บางอย่างอาจเปลี่ยนแปลงได้ขณะที่แอปทำงานอยู่ ซึ่งรวมถึงแต่ไม่จำกัดเพียง
- ขนาดการแสดงผลของแอป
- การวางแนวหน้าจอ
- ขนาดและน้ำหนักแบบอักษร
- ภาษา
- โหมดมืดเทียบกับโหมดสว่าง
- ความพร้อมใช้งานของแป้นพิมพ์
การเปลี่ยนแปลงการกำหนดค่าส่วนใหญ่เหล่านี้เกิดขึ้นเนื่องจากการโต้ตอบของผู้ใช้บางราย ตัวอย่างเช่น การหมุนหรือพับอุปกรณ์จะเปลี่ยนปริมาณพื้นที่หน้าจอที่แอปของคุณใช้ได้ ในทำนองเดียวกัน การเปลี่ยนการตั้งค่าอุปกรณ์ เช่น ขนาดแบบอักษร ภาษา หรือธีมที่ต้องการ จะเปลี่ยนค่าที่เกี่ยวข้องในออบเจ็กต์ Configuration
โดยปกติแล้ว พารามิเตอร์เหล่านี้ต้องมีการเปลี่ยนแปลง UI ของแอปพลิเคชันมากพอ
ที่แพลตฟอร์ม Android จะมีกลไกที่สร้างขึ้นโดยเฉพาะเมื่อมีการเปลี่ยนแปลง
กลไกนี้คือActivityการสร้างใหม่
การสร้างกิจกรรมใหม่
ระบบจะสร้าง Activity ขึ้นใหม่เมื่อมีการเปลี่ยนแปลงการกำหนดค่า โดยระบบจะเรียกใช้ onDestroy() และทำลายอินสแตนซ์ Activity ที่มีอยู่ จากนั้นจะ
สร้างอินสแตนซ์ใหม่โดยใช้ onCreate() และอินสแตนซ์ Activity ใหม่นี้จะ
เริ่มต้นด้วยการกำหนดค่าใหม่ที่อัปเดตแล้ว ซึ่งหมายความว่าระบบ
จะสร้าง UI ใหม่ด้วยการกำหนดค่าใหม่ด้วย
ลักษณะการทำงานของการสร้างใหม่ช่วยให้แอปพลิเคชันปรับให้เข้ากับการกำหนดค่าใหม่ได้โดย โหลดแอปพลิเคชันซ้ำโดยอัตโนมัติด้วยทรัพยากรสำรองที่ตรงกับ การกำหนดค่าอุปกรณ์ใหม่
ตัวอย่างการพักผ่อนหย่อนใจ
พิจารณาTextViewที่แสดงชื่อแบบคงที่โดยใช้
android:text="@string/title" ตามที่กำหนดไว้ในไฟล์ XML ของเลย์เอาต์ เมื่อสร้างมุมมอง ระบบจะตั้งค่าข้อความเพียงครั้งเดียวตามภาษาปัจจุบัน หาก
ภาษาเปลี่ยนแปลง ระบบจะสร้างกิจกรรมขึ้นใหม่ ด้วยเหตุนี้ ระบบจึงสร้างมุมมองขึ้นมาใหม่และเริ่มต้นมุมมองด้วยค่าที่ถูกต้องตามภาษาใหม่ด้วย
การสร้างใหม่ยังล้างสถานะที่เก็บไว้เป็นฟิลด์ใน
Activity หรือใน Fragment, View หรือออบเจ็กต์อื่นๆ ที่มีอยู่ เนื่องจากการสร้าง Activity ใหม่จะสร้างอินสแตนซ์ใหม่ทั้งหมดของ Activity
และ UI นอกจากนี้ Activity เก่าจะไม่ปรากฏหรือใช้งานได้อีกต่อไป ดังนั้นการอ้างอิงที่เหลืออยู่หรือออบเจ็กต์ที่อยู่ในนั้นจึงล้าสมัย ซึ่งอาจทำให้เกิด
ข้อบกพร่อง หน่วยความจำรั่ว และข้อขัดข้อง
ความคาดหวังของผู้ใช้
ผู้ใช้แอปคาดหวังให้ระบบเก็บสถานะไว้ หากผู้ใช้กำลังกรอกแบบฟอร์ม และเปิดแอปอื่นในโหมดหลายหน้าต่างเพื่ออ้างอิงข้อมูล การที่ผู้ใช้กลับมายังแบบฟอร์มที่ล้างไปแล้วหรือไปยัง ส่วนอื่นในแอปทั้งหมดถือเป็นประสบการณ์ที่ไม่ดีสำหรับผู้ใช้ ในฐานะนักพัฒนาแอป คุณต้องมอบประสบการณ์ของผู้ใช้ที่สอดคล้องกัน ผ่านการเปลี่ยนแปลงการกำหนดค่าและการสร้างกิจกรรมใหม่
หากต้องการยืนยันว่าแอปพลิเคชันของคุณยังคงรักษาสถานะไว้หรือไม่ คุณสามารถดำเนินการ ที่ทำให้เกิดการเปลี่ยนแปลงการกำหนดค่าทั้งขณะที่แอปทำงานอยู่เบื้องหน้าและ ขณะที่แอปทำงานอยู่เบื้องหลัง การทำงานดังกล่าว ได้แก่:
- การหมุนอุปกรณ์
- เข้าสู่โหมดหลายหน้าต่าง
- การปรับขนาดแอปพลิเคชันขณะอยู่ในโหมดหลายหน้าต่างหรือหน้าต่างแบบอิสระ
- การพับอุปกรณ์ที่พับได้ซึ่งมีหลายจอแสดงผล
- การเปลี่ยนธีมของระบบ เช่น โหมดมืดเทียบกับโหมดสว่าง
- การเปลี่ยนขนาดแบบอักษร
- การเปลี่ยนภาษาของระบบหรือแอป
- การเชื่อมต่อหรือยกเลิกการเชื่อมต่อแป้นพิมพ์ฮาร์ดแวร์
- การเชื่อมต่อหรือยกเลิกการเชื่อมต่อแท่นวาง
คุณใช้แนวทางหลักๆ 3 วิธีเพื่อรักษาสถานะที่เกี่ยวข้องผ่านการActivityสร้างใหม่ได้ โดยการเลือกใช้จะขึ้นอยู่กับประเภทสถานะที่ต้องการ
เก็บรักษา
- การคงอยู่ของข้อมูลในเครื่องเพื่อจัดการการสิ้นสุดการประมวลผลสำหรับข้อมูลที่ซับซ้อนหรือมีขนาดใหญ่
พื้นที่เก็บข้อมูลในเครื่องแบบถาวรรวมถึงฐานข้อมูลหรือ
DataStore - ออบเจ็กต์ที่เก็บไว้ เช่น อินสแตนซ์
ViewModelเพื่อจัดการสถานะที่เกี่ยวข้องกับ UI ใน หน่วยความจำขณะที่ผู้ใช้ใช้งานแอปอยู่ - สถานะอินสแตนซ์ที่บันทึกไว้เพื่อจัดการการสิ้นสุดการประมวลผลที่ระบบเริ่มต้นและเก็บสถานะชั่วคราวที่ขึ้นอยู่กับข้อมูลจากผู้ใช้หรือการนำทาง
หากต้องการอ่านเกี่ยวกับ API สำหรับแต่ละรายการเหล่านี้โดยละเอียด และเมื่อใดที่ควรใช้แต่ละรายการ โปรดดูบันทึกสถานะ UI
จำกัดการสร้างกิจกรรมใหม่
คุณป้องกันไม่ให้ระบบสร้างกิจกรรมขึ้นมาใหม่โดยอัตโนมัติสำหรับการเปลี่ยนแปลงการกำหนดค่าบางอย่างได้
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 12L (ระดับ API 32) ไม่ได้
ตอบสนองต่อการเปลี่ยนแปลงการกำหนดค่าในระบบมุมมอง
ในระบบ View เมื่อมีการเปลี่ยนแปลงการกำหนดค่าที่คุณปิดใช้การสร้าง Activity ใหม่ กิจกรรมจะได้รับการเรียกไปยัง Activity.onConfigurationChanged() มุมมองที่แนบมาจะได้รับการเรียกไปยัง View.onConfigurationChanged() ด้วย สำหรับการเปลี่ยนแปลงการกำหนดค่าที่คุณไม่ได้เพิ่มลงใน android:configChanges ระบบจะสร้างกิจกรรมขึ้นใหม่ตามปกติ
เมธอด Callback onConfigurationChanged() จะรับออบเจ็กต์ Configuration ที่ระบุการกำหนดค่าอุปกรณ์ใหม่ อ่านฟิลด์ในออบเจ็กต์ Configuration เพื่อดูว่าการกำหนดค่าใหม่ของคุณคืออะไร หากต้องการทำการเปลี่ยนแปลงในภายหลัง ให้อัปเดตทรัพยากรที่คุณใช้ในอินเทอร์เฟซ เมื่อระบบเรียกใช้เมธอดนี้ ระบบจะอัปเดตออบเจ็กต์ Resources ของกิจกรรมเพื่อแสดงผลทรัพยากรตามการกำหนดค่าใหม่
ซึ่งช่วยให้คุณรีเซ็ตองค์ประกอบของ UI ได้โดยไม่ต้องให้ระบบ
รีสตาร์ทกิจกรรม
ตัวอย่างเช่น การติดตั้งใช้งาน onConfigurationChanged() ต่อไปนี้จะตรวจสอบ
ว่ามีคีย์บอร์ดหรือไม่
Kotlin
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Checks whether a keyboard is available
if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show()
} else if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_NO) {
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show()
}
}
Java
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks whether a keyboard is available
if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show();
} else if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO){
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show();
}
}
หากไม่จำเป็นต้องอัปเดตแอปพลิเคชันตามการเปลี่ยนแปลงการกำหนดค่าเหล่านี้ คุณสามารถเลือกที่จะไม่ใช้ onConfigurationChanged() แทนได้ ในกรณีนี้ ระบบจะยังคงใช้ทรัพยากรทั้งหมดที่ใช้ก่อนการเปลี่ยนแปลงการกำหนดค่า
และคุณเพียงหลีกเลี่ยงการรีสตาร์ทกิจกรรมเท่านั้น เช่น แอป TV
อาจไม่ต้องการตอบสนองเมื่อมีการเชื่อมต่อหรือยกเลิกการเชื่อมต่อแป้นพิมพ์บลูทูธ
รักษาสถานะ
เมื่อใช้เทคนิคนี้ คุณยังคงต้องรักษาสถานะไว้ในระหว่างวงจรกิจกรรมปกติ เนื่องจากสาเหตุต่อไปนี้
- การเปลี่ยนแปลงที่หลีกเลี่ยงไม่ได้: การเปลี่ยนแปลงการกำหนดค่าที่คุณป้องกันไม่ได้อาจ รีสตาร์ทแอปพลิเคชัน
- การสิ้นสุดการประมวลผล: แอปพลิเคชันของคุณต้องสามารถจัดการการสิ้นสุดการประมวลผลที่ระบบเริ่มต้นได้ หากผู้ใช้ออกจากแอปพลิเคชันและแอปเข้าสู่ เบื้องหลัง ระบบอาจทำลายแอป
ตอบสนองต่อการเปลี่ยนแปลงการกำหนดค่าใน Jetpack Compose
Jetpack Compose ช่วยให้แอปตอบสนองต่อการเปลี่ยนแปลงการกำหนดค่าได้ง่ายขึ้น
อย่างไรก็ตาม หากคุณปิดใช้Activityการสร้างใหม่สำหรับการเปลี่ยนแปลงการกำหนดค่าทั้งหมดที่ทำได้ แอปของคุณยังคงต้องจัดการการเปลี่ยนแปลงการกำหนดค่าอย่างถูกต้อง
ออบเจ็กต์ Configuration พร้อมใช้งานในลำดับชั้น UI ของ Compose โดยมีLocalConfiguration องค์ประกอบเฉพาะที่ เมื่อใดก็ตามที่ค่าเปลี่ยน ฟังก์ชันที่ประกอบกันได้ซึ่งอ่านจาก LocalConfiguration.current จะทำการจัดองค์ประกอบใหม่ ดูข้อมูลเกี่ยวกับวิธีการทำงานของ CompositionLocal ได้ที่ข้อมูลที่กำหนดขอบเขตในเครื่อง
ด้วย 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 แสดงต่อผู้ใช้ เช่น ขนาดการแสดงผลแอป ภาษา หรือธีมของระบบ
- การเปลี่ยนแปลงการกำหนดค่า: การกำหนดค่าจะเปลี่ยนแปลงผ่านการโต้ตอบของผู้ใช้ เช่น ผู้ใช้อาจเปลี่ยนการตั้งค่าอุปกรณ์หรือวิธีโต้ตอบกับอุปกรณ์ ทางกายภาพ คุณไม่สามารถป้องกัน การเปลี่ยนแปลงการกำหนดค่าได้
Activityการสร้างใหม่: การเปลี่ยนแปลงการกำหนดค่าจะส่งผลให้เกิดการสร้างActivityใหม่ โดยค่าเริ่มต้น นี่คือกลไกในตัวเพื่อเริ่มต้นสถานะแอปใหม่สำหรับการกำหนดค่าใหม่Activityการทำลาย:Activityการสร้างใหม่ทำให้ระบบทำลายอินสแตนซ์Activityเก่า และสร้างอินสแตนซ์ใหม่แทนที่ อินสแตนซ์เก่า ล้าสมัยแล้ว การอ้างอิงที่เหลืออยู่จะส่งผลให้เกิดหน่วยความจำรั่ว ข้อบกพร่อง หรือข้อขัดข้อง- สถานะ: สถานะในอินสแตนซ์
Activityเก่าจะไม่มีในอินสแตนซ์Activityใหม่เนื่องจากเป็นอินสแตนซ์ออบเจ็กต์ที่แตกต่างกัน รักษาสถานะของแอปและผู้ใช้ตามที่อธิบายไว้ในบันทึกสถานะ UI - เลือกไม่ใช้: การเลือกไม่ใช้การสร้างกิจกรรมใหม่สําหรับการเปลี่ยนแปลงประเภทการกําหนดค่า เป็นการเพิ่มประสิทธิภาพที่อาจเกิดขึ้น โดยกำหนดให้แอปของคุณ อัปเดตอย่างถูกต้องเพื่อตอบสนองต่อการกำหนดค่าใหม่
โปรดปฏิบัติตามแนวทางปฏิบัติแนะนำต่อไปนี้เพื่อมอบประสบการณ์การใช้งานที่ดีให้แก่ผู้ใช้
- เตรียมพร้อมสำหรับการเปลี่ยนแปลงการกำหนดค่าบ่อยครั้ง: อย่าคิดว่าการเปลี่ยนแปลงการกำหนดค่าจะเกิดขึ้นไม่บ่อยหรือไม่มีเลย ไม่ว่าจะเป็นระดับ API, รูปแบบอุปกรณ์ หรือชุดเครื่องมือ UI เมื่อผู้ใช้ทำการเปลี่ยนแปลงการกำหนดค่า ผู้ใช้จะคาดหวังให้แอปอัปเดตและ ทำงานต่อไปอย่างถูกต้องด้วยการกำหนดค่าใหม่
- รักษาสถานะ: รักษาสถานะของผู้ใช้ไว้เมื่อเกิด
Activityการสร้างใหม่ เก็บรักษาสถานะตามที่อธิบายไว้ในบันทึกสถานะ UI - หลีกเลี่ยงการเลือกไม่ใช้เพื่อเป็นการแก้ไขด่วน: อย่าเลือกไม่ใช้
Activityการสร้างใหม่ เพื่อเป็นทางลัดในการหลีกเลี่ยงการสูญเสียสถานะ การเลือกไม่ใช้การสร้างกิจกรรมใหม่กำหนดให้คุณต้องทำตามสัญญาในการจัดการการเปลี่ยนแปลง และคุณอาจยังคงสูญเสียสถานะเนื่องจากActivityการสร้างใหม่จากการเปลี่ยนแปลงการกำหนดค่าอื่นๆ การสิ้นสุดกระบวนการ หรือการปิดแอป ไม่สามารถปิดใช้การสร้างActivityใหม่ได้ทั้งหมด เก็บรักษาสถานะตามที่อธิบายไว้ในบันทึกสถานะ UI - อย่าหลีกเลี่ยงการเปลี่ยนแปลงการกำหนดค่า: อย่าจำกัดการวางแนว
สัดส่วนภาพ หรือการปรับขนาดเพื่อหลีกเลี่ยงการเปลี่ยนแปลงการกำหนดค่าและ
Activityการสร้างใหม่ ซึ่งจะส่งผลเสียต่อผู้ใช้ที่ต้องการใช้แอปของคุณใน วิธีที่ตนเองต้องการ
จัดการการเปลี่ยนแปลงการกำหนดค่าตามขนาด
การเปลี่ยนแปลงการกำหนดค่าตามขนาดอาจเกิดขึ้นได้ทุกเมื่อ และมีแนวโน้มที่จะเกิดขึ้นมากขึ้น เมื่อแอปทำงานบนอุปกรณ์หน้าจอขนาดใหญ่ที่ผู้ใช้สามารถเข้าสู่โหมดหลายหน้าต่างได้ ผู้ใช้คาดหวังว่าแอปของคุณจะทำงานได้ดีในสภาพแวดล้อมดังกล่าว
การเปลี่ยนแปลงขนาดมี 2 ประเภทหลักๆ ได้แก่ การเปลี่ยนแปลงที่สำคัญและ การเปลี่ยนแปลงที่ไม่สำคัญ การเปลี่ยนแปลงขนาดอย่างมีนัยสำคัญคือการเปลี่ยนแปลงที่ชุดทรัพยากรสำรอง ที่แตกต่างกันมีผลกับการกำหนดค่าใหม่เนื่องจากความแตกต่างใน ขนาดหน้าจอ เช่น ความกว้าง ความสูง หรือความกว้างที่เล็กที่สุด ซึ่งรวมถึงทรัพยากรที่แอปกำหนดเองและทรัพยากรจากไลบรารีของแอป
จำกัดการสร้างกิจกรรมใหม่สำหรับการเปลี่ยนแปลงการกำหนดค่าตามขนาด
เมื่อปิดใช้การสร้าง Activity ใหม่สำหรับการเปลี่ยนแปลงการกำหนดค่าตามขนาด ระบบจะไม่สร้าง Activity ใหม่ แต่จะรับสายที่
Activity.onConfigurationChanged() แทน มุมมองที่แนบมาจะได้รับการโทรไปยัง
View.onConfigurationChanged()
ระบบจะปิดใช้การสร้างใหม่ Activity สำหรับการเปลี่ยนแปลงการกำหนดค่าตามขนาดเมื่อคุณมี
android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout"
ในไฟล์ Manifest
อนุญาตให้สร้างกิจกรรมใหม่สำหรับการเปลี่ยนแปลงการกำหนดค่าตามขนาด
ใน Android 7.0 (API ระดับ 24) ขึ้นไป Activityการสร้างใหม่จะเกิดขึ้นเฉพาะการเปลี่ยนแปลงการกำหนดค่าตามขนาดในกรณีที่ขนาดเปลี่ยนแปลงอย่างมีนัยสำคัญ เมื่อระบบไม่สร้าง Activity ใหม่เนื่องจากมีขนาดไม่เพียงพอ ระบบอาจเรียกใช้ Activity.onConfigurationChanged() และ View.onConfigurationChanged() แทน
ข้อควรระวังบางประการเกี่ยวกับแฮนเดิล Activity และ View
การเรียกกลับเมื่อไม่ได้สร้าง Activity ใหม่มีดังนี้
- ใน Android 11 (ระดับ API 30) ถึง Android 13 (ระดับ API 33) ระบบจะไม่เรียกใช้
Activity.onConfigurationChanged() - มีปัญหาที่ทราบแล้วซึ่งในบางกรณี
View.onConfigurationChanged()อาจไม่ได้รับการเรียกใช้ใน Android 12L (ระดับ API 32) และ Android 13 (ระดับ API 33) เวอร์ชันแรกๆ ดูข้อมูลเพิ่มเติมได้ที่ปัญหาสาธารณะนี้ เราได้แก้ไขปัญหานี้แล้วใน Android 13 รุ่นต่อๆ มาและ Android 14
สำหรับโค้ดที่ขึ้นอยู่กับการรอรับการเปลี่ยนแปลงการกำหนดค่าตามขนาด
เราขอแนะนำให้ใช้ยูทิลิตี View ที่มีการลบล้าง
View.onConfigurationChanged() แทนการพึ่งพาการสร้าง Activity ใหม่หรือ
Activity.onConfigurationChanged()