Configuration Changes เป็นหนึ่งในการทำงานของระบบแอนดรอยด์ที่ส่งผลต่อนักพัฒนาแอป เพราะนักพัฒนาจะต้องจัดการกับข้อมูลภายในแอปให้เหมาะสมเพื่อให้แอปสามารถทำงานได้อย่างถูกต้อง

บทความในชุดเดียวกัน

Configuration Changes คือ?

Configuration Changes คือเหตุการณ์ที่เกิดขึ้นเมื่อค่าบางอย่างภายในเครื่อง (Device Configuration) มีการเปลี่ยนแปลง และส่งผลต่อแอปที่ทำงานอยู่ในขณะนั้น ยกตัวอย่างเช่น การหมุนหน้าจอเพื่อเปลี่ยนจากการใช้งานแอปในแนวตั้งไปเป็นแนวนอน จึงทำให้ระบบแอนดรอยด์ต้องเปลี่ยนรูปแบบการทำงานให้เหมาะสมกับหน้าจอแนวนอนนั่นเอง

Configuration Changes เกิดขึ้นตอนไหน?

ปัจจัยทีทำให้เกิด Configutation Change นั้นมีอยู่หลายปัจจัยด้วยกัน ไม่ได้มีแค่การหมุนหน้าจออุปกรณ์แอนดรอยด์เพียงอย่างเดียว แต่จะเป็นการทำงานใด ๆ ก็ตามที่ส่งผลต่อการทำงานหรือการแสดง UI ภายในแอปที่ทำงานอยู่ ณ​ ตอนนั้น

และเมื่ออ้างอิงจากข้อมูลใน Activity Attributes [Android Developers] ก็จะพบว่ามีเหตุการณ์ที่ส่งผลให้เกิด Configuration Changes ดังนี้

  • Orientation – เปลี่ยนทิศทางในการแสดงผลของหน้าจอ (แนวตั้ง/แนวนอน)
  • Locale – เปลี่ยนภาษาที่ใช้ในการแสดงผล
  • UI Mode – เปลี่ยนรูปแบบในการทำงานของเครื่อง เช่น เปลี่ยนจาก Normal Mode ไปเป็น Dark Mode, Desk Mode, หรือ Car Mode เป็นต้น
  • Font Scale – เปลี่ยนขนาดตัวหนังสือที่ใช้ในการแสดงผล
  • Density – เปลี่ยนความละเอียดหน้าจอที่ทำให้ค่า Density ของหน้าจอเปลี่ยนไปจากเดิม
  • Screen Size และ Smallest Screen Size – เปลี่ยนขนาดหน้าจอในการแสดงผลแอปที่ใช้งานอยู่ในขณะนั้น
  • Color Mode – เปลี่ยนรูปแบบในการแสดงผลสีบนหน้าจอ
  • Navigation – เปลี่ยนรูปแบบในการแสดงผลของ Navigation Bar
  • Screen Layout – เปลี่ยนหน้าจอในการแสดงผล
  • Keyboard – เปลี่ยนรูปแบบการใช้งาน Keyboard
  • Layout Direction – เปลี่ยนการแสดงทิศทางของตัวหนังสือระหว่างซ้ายไปขวา (Left-to-right) กับขวาไปซ้าย (Right-to-left)
  • MCC และ MNC – มีการใส่ SIM Card และทำการอัปเดตข้อมูล Mobile Country Code หรือ Mobile Network Code

ถึงแม้ว่าจะมีหลายปัจจัยที่ทำให้เกิด Configuration Changes แต่จะมีแค่บางส่วนเท่านั้นที่เกิดขึ้นได้บ่อย เช่น UI Mode, Locale, และ Orientation

จะเกิดอะไรขึ้นเมื่อ Configuration Changes

เมื่อผู้ใช้ทำอะไรบางอย่างที่ทำให้ Configuration Changes เกิดขึ้น ระบบแอนดรอยด์จะทำการส่งค่า Configuration ใหม่ให้กับแอปที่กำลังทำงานอยู่ (รวมไปถึง System UI และแอปเคยเปิดไว้ก่อนหน้าแล้วเปิดใหม่อีกครั้งในภายหลังด้วย)

และสิ่งที่เกิดขึ้นในแต่ละแอปก็คือ Activity ที่ทำงานอยู่ ณ ตอนนั้นจะถูก Recreate (Destroy แล้ว Create ใหม่) เพื่ออัปเดตค่า Configuration ที่อยู่ใน Context ใหม่ทั้งหมด

เช่น ผู้ใช้หมุนหน้าจอจากแนวตั้งไปเป็นแนวนอน ค่าที่เก็บไว้ใน Context จากเดิมเป็น Configuration.ORIENTATION_PORTRAIT ก็จะกลายเป็น Configuration.ORIENTATION_LANDSCAPE แทน

และในระหว่าง Activity Recreation ถ้านักพัฒนาไม่ได้จัดการข้อมูลที่เก็บไว้ใน Activity ให้ถูกต้องก็จะทำให้ข้อมูลนั้นหายไปด้วย

Configuration Changes ส่งผลต่อ Android Resource ด้วยนะ

เมื่อเกิด Configuration Changes จะทำให้การเรียกข้อมูลใน Android Resource เปลี่ยนไปจากเดิมได้ โดยจะเป็นไปตามเงื่อนไขของ Configuration Qualifier (หรือ Resource Qualifier) ที่นักพัฒนาเตรียมไว้ในโปรเจค

ยกตัวอย่างเช่น ในโปรเจคมีการสร้าง UI แยกกันระหว่างหน้าจอแนวตั้งกับแนวนอน โดยแยก Resource Qualifier เป็น layout กับ layout-land

ในระหว่างการใช้งานในแนวตั้ง ระบบแอนดรอยด์จะใช้ข้อมูลจากใน layout และเมื่อผู้ใช้หมุนหน้าจอไปเป็นแนวนอน ก็จะทำให้ Configuration Changes เกิดขึ้นและเปลี่ยนข้อมูลใน Context ให้มีค่า Orientation เป็นแนวนอน ทำให้ Activity ถูก Recreate ใหม่เพื่อใช้ข้อมูลใน layout-land แทน

นักพัฒนาควรรับมือกับ Configuration Changes อย่างไร

การทำงานของ Configuration Changes จะส่งผลกระทบต่อการทำงานของแอปอย่างแน่นอน ดังนั้นนักพัฒนาจึงต้องหาทางจัดการให้เหมาะสม ซึ่งจะมีอยู่ 2 วิธีด้วยกัน

วิธีที่ 1 - จัดการกับ UI State ให้รองรับ Configuration Changes

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

วิธีนี้เป็นวิธีที่แนะนำมากที่สุด เพราะไม่แทรกแซงการทำงานของ Configuration Changes แต่จัดการกับ UI State ให้เหมาะสมแทน

ส่วนวิธีจัดการกับข้อมูลที่เป็น UI State นั้นจะขึ้นอยู่กับว่าข้อมูลเหล่านั้นอยู่ใน Component ตัวไหน เพราะข้อมูลที่เก็บไว้ใน Activity, Fragment, View, และ Compose จะมีวิธีจัดการแตกต่างกัน

วิธีที่ 2 - Override เพื่อจัดการด้วยตัวเอง

ถ้าไม่ต้องการให้บาง Configuration เกิดเป็น Configuration Changes สามารถกำหนด android:configChanges ใน Android Manifest แบบนี้ได้

<?xml version="1.0" encoding="utf-8"?>
<manifest>
    <application>
        <activity 
            ...
            android:configChanges="screenSize|orientation" >
        </activity>
    </application>
</manifest>

เมื่อกำหนด XML Attribute ตัวนี้ไว้ใน Activity ใด ๆ จะทำให้ระบบแอนดรอยด์ข้ามการอัปเดต Context เมื่อเกิด Configuration Changes และจะส่งมาบอก Activity ผ่าน onConfigurationChanged(...) แทน เพื่อให้นักพัฒนาจัดการกับ Configuration ที่เปลี่ยนแปลงด้วยตัวเอง

// MainActivity.kt
class MainActivity : AppCompatActivity() {

    override fun onConfigurationChanged(newConfig: Configuration) {
        // Configuration has been changed
        
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            // Handle landscape screen orientation
        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
            // Handle portrait screen orientation
        }
    }
}

โดย onConfigurationChanged(...) จะทำงานก็ต่อเมื่อนักพัฒนากำหนดค่า Configuration นั้น ๆ ไว้ใน android:configChanges เท่านั้น ดังนั้นถ้า Configuration อื่นมีการเปลี่ยนแปลงก็จะทำให้เกิด Configuration Changes และส่งผลให้ Activity ถูก Recreate ใหม่อยู่ดี

ความเข้าใจผิดเกี่ยวกับ Configuration Changes

มีนักพัฒนาหลายคนที่เข้าใจผิดเกี่ยวกับการทำงานของ Configuration Changes และนำไปสู่การเขียนโค้ดที่ผิดวิธีและทำให้เกิดปัญหากับแอปในภายหลัง

Override ด้วย android:configChanges ใน Android Manifest แล้วไม่ต้องทำอะไร

ต่อให้การกำหนดค่าดังกล่าวให้กับ Activity จะช่วยให้ไม่เกิด Configuration Changes ก็จริง แต่นักพัฒนาก็ต้องจัดการกับการทำงานของแอปให้เหมาะสมกับ Configuration ที่มีการเปลี่ยนแปลงอยู่ดี

เช่น ถ้าแอปรองรับภาษาอังกฤษและภาษาไทย และไม่ได้มีฟีเจอร์เกี่ยวกับการเปลี่ยนภาษา เมื่อผู้ใช้เปลี่ยนภาษาในเครื่องจากภาษาอังกฤษไปเป็นภาษาไทย แอปก็ควรจะเปลี่ยนภาษาตามการตั้งค่าภายในเครื่องด้วย

ใช้ onConfigurationChanged เพื่อเช็คค่าบางอย่างใน Configuration

ถ้าอยากรู้ว่าหน้าจอแสดงผลเป็นแนวตั้งหรือแนวนอนอยู่ ก็ให้กำหนด android:configChanges="orientation" ให้กับ Activity ที่ต้องการ แล้วเช็คค่า Orientation ที่ได้จากคำสั่ง onConfigurationChanged(...)

ซึ่งจริง ๆ แล้วนักพัฒนาสามารถเช็คค่า Configuration จากใน Context ได้เลย และคำสั่ง onConfigurationChaged(...) มีไว้จัดการกับ Configuration ที่เปลี่ยนแปลงเพื่อให้แอปทำงานต่อจากเดิมได้อย่างทุกต้องเท่านั้น

ดังนั้นการใช้คำสั่งดังกล่าวเพื่อเช็คค่าใน Configuration เพียงอย่างเดียวก็อาจจะทำให้แอปทำงานไม่ถูกต้องเมื่อเกิด Configuration Changes ได้

ปัญหาการทำงานของ onConfigurationChanged บน Android 7.0 / 7.1 Nougat

โดยปกติคำสั่ง onConfigurationChanged(...) จะทำงานก็ต่อเมื่อมีการกำหนดค่า android:configChanges ให้กับ Activity ใด ๆ ใน Android Manifest

แต่บน Android 7.0 / 7.1 Nougat (API 24-25) จะมีปัญหาว่าคำสั่ง onConfigurationChanged(...) ทำงานทุกครั้งเมื่อเกิด Configuration Changes ถึงแม้จะไม่ได้กำหนดค่าใด ๆ ใน android:configChanges เลย ซึ่งทีมแอนดรอยด์แก้ปัญหานี้ไปใน Android 7.1.1 Nougat (อ้างอิงจาก https://issuetracker.google.com/issues/37120330)

ถ้ามีการเพิ่มคำสั่งไว้ใน onConfigurationChanged(...) ก็ควรเช็คให้ดีว่าได้รับผลกระทบหรือไม่ แต่ถ้าไม่ได้มีการเรียกใช้คำสั่งดังกล่าวอยู่แล้วก็ไม่มีปัญหาอะไร เพราะไม่ใช่อุปกรณ์แอนดรอยด์ทุกเครื่องที่เป็น Android 7.0 หรือ 7.1 แล้วจะได้รับอัปเดตเป็น 7.1.1

วิธีทดสอบ Configuration Changes

นักพัฒนาสามารถทดสอบ Configuration Changes กับแอปของตัวเองได้ด้วยการเปลี่ยนการตั้งค่าภายในเครื่องที่ทำให้เกิด Configuration Changes เช่น เปิด/ปิด Dark Theme, เปลี่ยนภาษาเครื่อง, ใช้งานแอปแบบ Split Screen หรือ Floating Window แล้วปรับขนาดหน้าต่าง เป็นต้น

วิธีที่สะดวกและรวดเร็วที่สุดก็คือการเปิด/ปิด Dark Theme ผ่าน Quick Settings ที่อยู่ใน Notification Tray

และถ้าใช้ Android Emulator บน Android Studio ก็จะสะดวกมากขึ้นกว่าเดิมอีก เพราะนักพัฒนาสามารถเปิด/ปิด Dark Theme ผ่านปุ่ม Device UI Shortcuts ได้เลย

แอปไม่จำเป็นต้องรองรับ Dark Theme ก็สามารถทดสอบ Configuration Changes ด้วยวิธีนี้ได้

สรุป

Configuration Changes นั้นเป็นหนึ่งในการทำงานของระบบแอนดรอยด์ที่นักพัฒนาควรจะรู้และเข้าใจ เพื่อจัดการกับ UI State ให้เหมาะสมกับการทำงานของ Configuration Changes เพื่อลดปัญหาที่อาจจะเกิดขึ้นจากการใช้งานทั่วไปของผู้ใช้

และอย่าลืมว่าการทำงานของ Configuration Changes นั้นจะส่งผลต่อ Android Resource ด้วย จึงทำให้นักพัฒนาสามารถใช้ประโยชน์จาก Configuration Qualifier (Resource Qualifier) เพื่อทำให้แอปสามารถรองรับการใช้งานได้หลากหลายรูปแบบโดยอ้างอิงจาก Configuration ณ ตอนนั้นได้

แหล่งอ้างอิงข้อมูล