การบันทึกสถานะด้วยส่วนย่อย

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

ตารางต่อไปนี้แสดงการดำเนินการที่ทำให้ข้อมูลโค้ดโค้ดเสียสถานะ รวมถึงระบุว่าสถานะประเภทต่างๆ จะยังคงอยู่หลังจากการเปลี่ยนแปลงเหล่านั้นหรือไม่ ประเภทสถานะที่กล่าวถึงในตารางมีดังนี้

  • ตัวแปร: ตัวแปรภายในของข้อมูลโค้ด
  • สถานะมุมมอง: ข้อมูลใดก็ตามที่มุมมองอย่างน้อย 1 รายการเป็นเจ้าของในส่วนข้อมูล
  • SavedState: ข้อมูลที่มีอยู่ในอินสแตนซ์ของ Fragment นี้ซึ่งควรบันทึกใน onSaveInstanceState()
  • NonConfig: ข้อมูลที่ดึงมาจากแหล่งที่มาภายนอก เช่น เซิร์ฟเวอร์หรือที่เก็บข้อมูลในเครื่อง หรือข้อมูลที่ผู้ใช้สร้างขึ้นซึ่งส่งไปยังเซิร์ฟเวอร์เมื่อคอมมิตแล้ว

บ่อยครั้งที่ตัวแปรได้รับการปฏิบัติเช่นเดียวกับ SavedState แต่ตารางต่อไปนี้จะแยกความแตกต่างระหว่าง 2 รายการนี้เพื่อแสดงให้เห็นผลของการดำเนินการต่างๆ กับแต่ละรายการ

การดำเนินการ ตัวแปร ดูสถานะ SavedState ไม่มีการกำหนดค่า
เพิ่มลงในกองซ้อนที่ซ้อนกัน x
การเปลี่ยนแปลงการกําหนดค่า x
การสิ้นสุดการประมวลผล/การสร้างใหม่ x ✓*
Removed not added to back stack x x x x
โฮสต์เสร็จแล้ว x x x x

* สามารถเก็บรักษาสถานะ NonConfig ไว้ตลอดกระบวนการสูงสุดได้โดยใช้โมดูล "Saved State" สำหรับ ViewModel

ตารางที่ 1: การดำเนินการที่ทำลายข้อมูลในรายการต่างๆ ของรายการย่อยและผลที่การดำเนินการเหล่านั้นมีต่อสถานะประเภทต่างๆ

เรามาดูตัวอย่างที่เจาะจงกัน พิจารณาหน้าจอที่สร้างสตริงแบบสุ่ม แสดงใน TextView และมีตัวเลือกให้แก้ไขสตริงก่อนที่จะส่งให้เพื่อน

แอปสร้างข้อความแบบสุ่มที่แสดงสถานะประเภทต่างๆ
รูปที่ 1 แอปสร้างข้อความแบบสุ่มที่แสดงสถานะประเภทต่างๆ

ในตัวอย่างนี้ สมมติว่าเมื่อผู้ใช้กดปุ่มแก้ไข แอปจะแสดงมุมมอง EditText ที่ผู้ใช้แก้ไขข้อความได้ หากผู้ใช้คลิกยกเลิก ระบบควรล้างมุมมอง EditText และตั้งค่าระดับการมองเห็นเป็น View.GONE หน้าจอดังกล่าวอาจต้องจัดการข้อมูล 4 รายการเพื่อให้ได้รับประสบการณ์การใช้งานที่ราบรื่น

ข้อมูล ประเภท ประเภทสถานะ คำอธิบาย
seed Long NonConfig เมล็ดพันธุ์ที่ใช้สําหรับสร้างการกระทําดีใหม่แบบสุ่ม สร้างขึ้นเมื่อสร้าง ViewModel
randomGoodDeed String SavedState + ตัวแปร สร้างขึ้นเมื่อสร้างข้อมูลโค้ดครั้งแรก ระบบจะบันทึก randomGoodDeed ไว้เพื่อให้ผู้ใช้เห็นการกระทำดีแบบสุ่มแบบเดียวกันหลังจากที่กระบวนการเสียชีวิตและการสันทนาการไปแล้ว
isEditing Boolean SaveState + ตัวแปร ตั้งค่า Flag บูลีนเป็น true เมื่อผู้ใช้เริ่มแก้ไข isEditing จะถูกบันทึกไว้เพื่อให้แน่ใจว่าส่วนการแก้ไขของหน้าจอจะยังคงมองเห็นได้เมื่อสร้างข้อมูลโค้ดโค้ดอีกครั้ง
ข้อความที่แก้ไข Editable สถานะการดู (เป็นของ EditText) ข้อความที่แก้ไขในมุมมอง EditText มุมมอง EditText จะบันทึกข้อความนี้เพื่อไม่ให้การเปลี่ยนแปลงที่อยู่ระหว่างดำเนินการของผู้ใช้สูญหายไป

ตารางที่ 2: ระบุว่าแอปสร้างข้อความแบบสุ่มต้องจัดการ

ส่วนต่อไปนี้อธิบายวิธีจัดการสถานะของข้อมูลอย่างถูกต้องผ่านการดำเนินการแบบทำลาย

ดูสถานะ

มุมมองมีหน้าที่รับผิดชอบในการจัดการสถานะของตนเอง เช่น เมื่อมุมมองยอมรับอินพุตของผู้ใช้ มุมมองมีหน้าที่รับผิดชอบในการบันทึกและกู้คืนอินพุตนั้นเพื่อจัดการการเปลี่ยนแปลงการกําหนดค่า มุมมองทั้งหมดที่เฟรมเวิร์ก Android มีให้จะใช้ onSaveInstanceState() และ onRestoreInstanceState() ของตัวเอง คุณจึงไม่ต้องจัดการสถานะมุมมองภายในฟragment

ตัวอย่างเช่น ในสถานการณ์สมมติก่อนหน้านี้ ระบบจะเก็บสตริงที่แก้ไขไว้ใน EditText EditText จะทราบค่าของข้อความที่แสดง รวมถึงรายละเอียดอื่นๆ เช่น ต้นและท้ายของข้อความที่เลือก

ข้อมูลพร็อพเพอร์ตี้จำเป็นต้องมีรหัสเพื่อคงสถานะไว้ รหัสนี้ต้องไม่ซ้ำกันภายในกลุ่มและลําดับชั้นมุมมองของกลุ่ม ข้อมูลพร็อพเพอร์ตี้ที่ไม่มีรหัสจะเก็บสถานะไว้ไม่ได้

<EditText
    android:id="@+id/good_deed_edit_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

ดังที่กล่าวไว้ในตารางที่ 1 มุมมองจะบันทึกและกู้คืนViewStateผ่านการดำเนินการทั้งหมดที่ไม่ได้นำข้อมูลโค้ดย่อยออกหรือทำลายโฮสต์

SavedState

ข้อมูลโค้ดจะมีหน้าที่จัดการสถานะแบบไดนามิกจํานวนเล็กน้อยซึ่งสําคัญต่อวิธีทํางานของข้อมูลโค้ด คุณสามารถเก็บรักษาข้อมูลที่ซีเรียลไลซ์ได้ง่ายโดยใช้ Fragment.onSaveInstanceState(Bundle) ข้อมูลที่คุณใส่ไว้ในแพ็กเกจจะยังคงอยู่แม้มีการเปลี่ยนแปลงการกําหนดค่า รวมถึงเมื่อกระบวนการสิ้นสุดและสร้างใหม่ และข้อมูลดังกล่าวจะอยู่ในเมธอด onCreate(Bundle), onCreateView(LayoutInflater, ViewGroup, Bundle) และ onViewCreated(View, Bundle) ของข้อมูลโค้ดActivity.onSaveInstanceState(Bundle)

จากตัวอย่างก่อนหน้านี้ randomGoodDeed คือการกระทำที่แสดงต่อผู้ใช้ และ isEditing คือ Flag เพื่อระบุว่าจะแสดงหรือซ่อน EditText สถานะที่บันทึกไว้นี้ควรคงอยู่โดยใช้ onSaveInstanceState(Bundle) ตามที่แสดงในตัวอย่างต่อไปนี้

Kotlin

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putBoolean(IS_EDITING_KEY, isEditing)
    outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed)
}

Java

@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBoolean(IS_EDITING_KEY, isEditing);
    outState.putString(RANDOM_GOOD_DEED_KEY, randomGoodDeed);
}

หากต้องการกู้คืนสถานะใน onCreate(Bundle) ให้เรียกข้อมูลค่าที่เก็บไว้จากแพ็กเกจ โดยทำดังนี้

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    isEditing = savedInstanceState?.getBoolean(IS_EDITING_KEY, false)
    randomGoodDeed = savedInstanceState?.getString(RANDOM_GOOD_DEED_KEY)
            ?: viewModel.generateRandomGoodDeed()
}

Java

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        isEditing = savedInstanceState.getBoolean(IS_EDITING_KEY, false);
        randomGoodDeed = savedInstanceState.getString(RANDOM_GOOD_DEED_KEY);
    } else {
        randomGoodDeed = viewModel.generateRandomGoodDeed();
    }
}

ดังที่กล่าวไว้ในตารางที่ 1 โปรดทราบว่าระบบจะเก็บตัวแปรไว้เมื่อวางข้อมูลโค้ดในกองซ้อนด้านหลัง การจัดการกับสถานะเหล่านี้เป็นสถานะที่บันทึกไว้จะช่วยให้สถานะดังกล่าวคงอยู่ตลอดการดำเนินการที่ทำลายข้อมูลทั้งหมด

ไม่มีการกำหนดค่า

ข้อมูล NonConfig ควรอยู่นอกส่วนของข้อมูล เช่น ใน ViewModel ในตัวอย่างก่อนหน้าด้านบน seed (สถานะ NonConfig ของเรา) จะสร้างขึ้นใน ViewModel ViewModel เป็นเจ้าของตรรกะในการรักษาสถานะ

Kotlin

public class RandomGoodDeedViewModel : ViewModel() {
    private val seed = ... // Generate the seed

    private fun generateRandomGoodDeed(): String {
        val goodDeed = ... // Generate a random good deed using the seed
        return goodDeed
    }
}

Java

public class RandomGoodDeedViewModel extends ViewModel {
    private Long seed = ... // Generate the seed

    private String generateRandomGoodDeed() {
        String goodDeed = ... // Generate a random good deed using the seed
        return goodDeed;
    }
}

คลาส ViewModel จะช่วยให้ข้อมูลคงอยู่จากการเปลี่ยนแปลงการกำหนดค่า เช่น การหมุนหน้าจอ และจะยังอยู่ในหน่วยความจำเมื่อวางส่วนย่อยในแบ็กสแต็ก หลังจากกระบวนการสิ้นสุดและสร้างใหม่ ระบบจะสร้าง ViewModel ขึ้นมาใหม่และสร้าง seed ใหม่ การเพิ่มข้อบังคับ SavedState ลงใน ViewModel จะช่วยให้ ViewModel คงสถานะแบบง่ายไว้ได้แม้จะมีการหยุดทำงานและสร้างใหม่

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

ดูข้อมูลเพิ่มเติมเกี่ยวกับการจัดการสถานะส่วนย่อยได้ที่ทรัพยากรเพิ่มเติมต่อไปนี้

Codelab

เส้นนำ