LifecycleOwner — เป็นอินเทอร์เฟซหลักจากไลบรารี Android Jetpack ที่ประกาศว่าอ็อบเจ็กต์มีวงจรชีวิตและให้การเข้าถึงผ่านเมธอด getLifecycle() มันเป็นรากฐานของสถาปัตยกรรมคอมโพเนนต์ของแอปพลิเคชัน Android สมัยใหม่ ช่วยแยกตรรกะการจัดการวงจรชีวิตออกจากการ implement เฉพาะของ Activity หรือ Fragment ตามข้อมูลของ Google I/O 2024 กว่า 85% ของโปรเจกต์ Android ใหม่ใช้ LifecycleOwner เพื่อจัดการการสมัครรับข้อมูลและป้องกันการรั่วไหลของหน่วยความจำ อินเทอร์เฟซนี้เป็นพื้นฐานสำหรับ LiveData, ViewModel และคอมโพเนนต์ Jetpack อื่นๆ เพื่อให้แน่ใจว่าการทำงานของโค้ดที่ปลอดภัยเฉพาะในสถานะที่คอมโพเนนต์ทำงานอยู่
ประเด็นสำคัญ
LifecycleOwner — เป็นอินเทอร์เฟซจากแพ็คเกจ androidx.lifecycle ที่มีเมธอดเดียว getLifecycle() ซึ่งส่งคืนอ็อบเจ็กต์ Lifecycle อ็อบเจ็กต์นี้จะติดตามสถานะปัจจุบันของคอมโพเนนต์ (CREATED, STARTED, RESUMED, DESTROYED) และแจ้งให้ผู้สังเกตการณ์ที่สมัครรับข้อมูลทั้งหมดทราบเมื่อมีการเปลี่ยนแปลง LifecycleOwner เป็นส่วนหนึ่งของ Architecture Components และรวมอยู่ในไลบรารี lifecycle-runtime
หน้าที่หลักของอินเทอร์เฟซคือ การทำให้การเข้าถึงวงจรชีวิตเป็นมาตรฐาน ก่อน Jetpack นักพัฒนาใช้การสมัครด้วยตนเองใน onStart และยกเลิกใน onStop ซึ่งนำไปสู่การซ้ำซ้อนของโค้ดและข้อผิดพลาด LifecycleOwner แก้ปัญหานี้โดยให้กลไก统一สำหรับคอมโพเนนต์ Android ทั้งหมด แทนที่จะเรียกเมธอดวงจรชีวิตอย่างชัดเจน นักพัฒนาสมัครรับ Lifecycle เพียงครั้งเดียวและการแจ้งเตือนจะมาโดยอัตโนมัติ
อินเทอร์เฟซถูกประกาศใน Kotlin เป็นอินเทอร์เฟซเชิงฟังก์ชันที่มีเมธอดนามธรรมเดียว:
interface LifecycleOwner {
val lifecycle: Lifecycle
}
ด้วยลักษณะเชิงฟังก์ชันของอินเทอร์เฟซ ทำให้ implement ได้ง่ายโดยใช้ delegate หรือ lambda ซึ่งสะดวกเป็นพิเศษสำหรับการสร้าง Custom Views และคลาส ViewModel ที่ต้องตอบสนองต่อการเปลี่ยนแปลงวงจรชีวิตของโฮสต์ อ็อบเจ็กต์ Lifecycle ที่ได้จาก getLifecycle() มีเมธอด addObserver และ removeObserver สำหรับจัดการการสมัครรับข้อมูล
LifecycleOwner ทำงานร่วมกับสองคลาสหลัก: Lifecycle และ LifecycleObserver Lifecycle จัดเก็บสถานะปัจจุบันของคอมโพเนนต์เป็น enum State (INITIALIZED, CREATED, STARTED, RESUMED, DESTROYED) และติดตามการเปลี่ยนผ่านระหว่างสถานะ เมื่อสถานะเปลี่ยนแปลง Lifecycle จะแจ้งผู้สังเกตการณ์ที่ลงทะเบียนทั้งหมด โดยเรียกเมธอดที่มีคำอธิบายประกอบที่เกี่ยวข้อง กลไกนี้เรียกว่า "lifecycle-aware" — โค้ดจะทำงานก็ต่อเมื่อคอมโพเนนต์อยู่ในสถานะที่เหมาะสม
กลไกการส่งเหตุการณ์ขึ้นอยู่กับรูปแบบ Observer LifecycleOwner ทำหน้าที่เป็น Observable และการ implement LifecycleObserver ทำหน้าที่เป็น Observer Activity หรือ Fragment เมื่อเปลี่ยนสถานะ (onCreate → onStart → onResume → onPause → onStop → onDestroy) จะแจ้ง Lifecycle ผ่านกลไกภายใน ReportFragment ซึ่งถูกเพิ่มเข้าไปในระบบ AndroidX โดยอัตโนมัติ นักพัฒนาไม่ต้องเรียกเมธอด Lifecycle ด้วยตนเอง — ทุกอย่างเกิดขึ้นโดยอัตโนมัติ
| สถานะ Lifecycle | เหตุการณ์ | เมธอดวงจรชีวิต Android |
|---|---|---|
| INITIALIZED | — | ก่อน onCreate |
| CREATED | ON_CREATE | onCreate |
| STARTED | ON_START | onStart |
| RESUMED | ON_RESUME | onResume |
| STARTED | ON_PAUSE | onPause |
| CREATED | ON_STOP | onStop |
| DESTROYED | ON_DESTROY | onDestroy |
รายละเอียดสำคัญ: Lifecycle รับประกันว่าเหตุการณ์ ON_STOP และ ON_DESTROY จะถูกส่งแม้ในกรณีที่กระบวนการขัดข้อง ทำให้ LifecycleOwner เป็นเครื่องมือที่เชื่อถือได้สำหรับการปล่อยทรัพยากรที่สำคัญ สำหรับการบันทึกสถานะปกติ แนะนำให้ใช้ SavedStateHandle ใน ViewModel แต่ LifecycleOwner ให้ระดับความปลอดภัยพื้นฐาน
มีสองวิธีในการสมัครรับเหตุการณ์ของ LifecycleOwner: LifecycleObserver แบบคลาสสิกพร้อมคำอธิบายประกอบ และ DefaultLifecycleObserver แบบสมัยใหม่พร้อมเมธอดที่ชัดเจน วิธีที่สองได้รับการแนะนำโดย Google ตั้งแต่ปี 2022 เนื่องจากมีความปลอดภัยของประเภทที่ดีกว่าและหลีกเลี่ยงการสะท้อน (reflection) ที่ใช้ในวิธีคำอธิบายประกอบ DefaultLifecycleObserver ต้องการ Java 8+ หรือ Kotlin และเป็นที่นิยมสำหรับโปรเจกต์ใหม่
ตัวอย่างการสมัครผ่าน DefaultLifecycleObserver:
class MyObserver : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
// เริ่มติดตาม GPS เฉพาะเมื่อคอมโพเนนต์ทำงานอยู่
startLocationUpdates()
}
override fun onStop(owner: LifecycleOwner) {
// หยุดอย่างปลอดภัยเมื่อเปลี่ยนเป็นโหมดพื้นหลัง
stopLocationUpdates()
}
}
// การเชื่อมต่อ:
lifecycleOwner.lifecycle.addObserver(MyObserver())
แต่ละเมธอดของ DefaultLifecycleObserver รับ LifecycleOwner เป็นพารามิเตอร์ ซึ่งช่วยให้ผู้สังเกตการณ์เข้าถึงบริบทของคอมโพเนนต์ที่กำลังทำงานได้โดยไม่ต้องส่งแยกต่างหาก วิธีนี้ทำให้โค้ดเป็นโมดูลาร์และทดสอบได้มากขึ้น — Observer ไม่ขึ้นอยู่กับการ implement เฉพาะของ Activity หรือ Fragment แต่ทำงานกับนามธรรม LifecycleOwner
วิธีเก่าที่ใช้คำอธิบายประกอบ @OnLifecycleEvent ยังคงพบได้ในโปรเจกต์เก่า แต่ไม่แนะนำให้ใช้สำหรับโค้ดใหม่ การสะท้อนที่จำเป็นสำหรับการประมวลผลคำอธิบายประกอบเพิ่มค่าใช้จ่ายและอาจนำไปสู่ข้อผิดพลาดที่ไม่ถูกตรวจพบในขณะคอมไพล์ Google แนะนำอย่างเป็นทางการให้ย้ายไปใช้ DefaultLifecycleObserver
// วิธีการเก่า — ไม่แนะนำสำหรับโปรเจกต์ใหม่
class MyLegacyObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
startLocationUpdates()
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
stopLocationUpdates()
}
}
วิธีคำอธิบายประกอบมีข้อเสียที่สำคัญ: ขาดการควบคุมอายุการใช้งาน ของ Observer หากนักพัฒนาลืมยกเลิกการสมัคร Observer เมื่อ LifecycleOwner ถูกทำลาย อ็อบเจ็กต์ Observer จะยังคงอยู่ในหน่วยความจำจนกว่าจะมีการเรียก garbage collector DefaultLifecycleObserver แก้ปัญหานี้ — Observer ผูกกับ Lifecycle และยกเลิกการสมัครโดยอัตโนมัติเมื่อเปลี่ยนไปยังสถานะ DESTROYED
ตั้งแต่ AppCompat 1.1.0 และ AndroidX Fragment 1.2.0 Activity และ Fragment ทั้งหมดที่สืบทอดจาก AppCompatActivity หรือ Fragment จะเป็น LifecycleOwner โดยอัตโนมัติ ซึ่งหมายความว่าเมธอด getLifecycle() พร้อมใช้งานโดยค่าเริ่มต้นและการสมัครรับเหตุการณ์วงจรชีวิตทำงานโดยไม่ต้องกำหนดค่าเพิ่มเติม นักพัฒนาเพียงแค่เรียก lifecycle.addObserver() จากที่ใดก็ได้ใน Activity หรือ Fragment
มาดูตัวอย่างการรวม LifecycleOwner ใน Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycle.addObserver(LocationObserver(this))
}
}
ในตัวอย่างนี้ lifecycle เป็น extension property ที่พร้อมใช้งานได้จาก AndroidX Activity ผู้สังเกตการณ์ LocationObserver จะได้รับการแจ้งเตือนเกี่ยวกับการเริ่มต้น (ON_START) และการหยุด (ON_STOP) ของ Activity โดยอัตโนมัติ เมื่อหมุนหน้าจอ Observer จะได้รับการแจ้งเตือนเกี่ยวกับ ON_DESTROY และจากนั้น ON_CREATE ซึ่งช่วยให้จัดการการเปลี่ยนแปลงการกำหนดค่าได้อย่างถูกต้องโดยไม่ต้องใช้โค้ดเพิ่มเติม
Fragment implement LifecycleOwner ผ่านอินเทอร์เฟซ และ Lifecycle ของมันผูกกับวงจรชีวิตของ Fragment ไม่ใช่ Activity หลัก นี่เป็นสิ่งสำคัญ: Lifecycle ของ Fragment เปลี่ยนเป็น DESTROYED เมื่อ Fragment ถูกลบออกจากธุรกรรม ในขณะที่ Activity สามารถอยู่ใน RESUMED ได้ ความแตกต่างนี้ช่วยให้ Observer สมัครรับวงจรชีวิตของแต่ละคอมโพเนนต์แยกกัน
class MyFragment : Fragment() {
private val uiStateObserver = UiStateObserver()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycle.addObserver(uiStateObserver)
}
}
ข้อได้เปรียบสำคัญของการใช้ LifecycleOwner ใน Fragment คือ การยกเลิกการสมัครโดยอัตโนมัติ เมื่อ Fragment เปลี่ยนเป็น DESTROYED ซึ่งมีความสำคัญเป็นพิเศษสำหรับ ViewPager ที่ Fragment สามารถถูกสร้างและทำลายแบบไดนามิก การจัดการการสมัครด้วยตนเองในสถานการณ์นี้จะซับซ้อนอย่างยิ่งและมีแนวโน้มเกิดข้อผิดพลาด
อินเทอร์เฟซ LifecycleOwner สามารถ implement ในคลาสใดก็ได้ที่มีวงจรชีวิต ซึ่งมีประโยชน์สำหรับ Custom Views, Services และแม้แต่ ViewModel ในโซลูชันทางสถาปัตยกรรมบางอย่าง Google มีคลาสช่วย LifecycleRegistry ที่จัดการสถานะของ Lifecycle และสร้างเหตุการณ์ นักพัฒนาต้องเรียกเมธอดที่เกี่ยวข้องของ LifecycleRegistry ด้วยตนเองเมื่อสถานะของคอมโพเนนต์เปลี่ยนไป
ตัวอย่างการ implement LifecycleOwner ใน Custom View:
class MyCustomView(
context: Context,
attrs: AttributeSet?
) : FrameLayout(context, attrs), LifecycleOwner {
private val lifecycleRegistry = LifecycleRegistry(this)
override val lifecycle: Lifecycle
get() = lifecycleRegistry
fun onStart() {
lifecycleRegistry.setCurrentState(Lifecycle.State.STARTED)
}
fun onStop() {
lifecycleRegistry.setCurrentState(Lifecycle.State.CREATED)
}
}
ในตัวอย่างนี้ LifecycleRegistry ทำหน้าที่เป็นที่เก็บสถานะ เมธอด onStart/onStop ควรถูกเรียกโดยคอมโพเนนต์หลัก (เช่น Activity) เมื่อ Custom View ปรากฏหรือถูกซ่อน LifecycleRegistry จะคำนวณเหตุการณ์ที่จำเป็นสำหรับการเปลี่ยนระหว่างสถานะโดยอัตโนมัติและแจ้ง Observer ที่สมัครรับข้อมูลทั้งหมด
เมื่อ implement LifecycleOwner ของตัวเอง สิ่งสำคัญคือต้องปฏิบัติตามกฎ: ควรอัปเดตสถานะของ LifecycleRegistry เป็นลำดับสุดท้ายในเมธอดวงจรชีวิตที่เกี่ยวข้อง หลังจากการดำเนินการอื่นๆ ทั้งหมด เพื่อให้แน่ใจว่า Observer ได้รับการแจ้งเตือนเมื่อคอมโพเนนต์พร้อมอย่างสมบูรณ์สำหรับสถานะใหม่ การใช้ LifecycleRegistry.createUnsafe เป็นทางเลือกก็เป็นไปได้ แต่ต้องระมัดระวังเกี่ยวกับเธรด
LifecycleOwner เป็นรากฐานสำหรับคอมโพเนนต์หลักหลายตัวของ Android Jetpack LiveData ใช้ LifecycleOwner เพื่อกำหนดสถานะที่ทำงานอยู่และยกเลิกการสมัครโดยอัตโนมัติเมื่อคอมโพเนนต์ถูกทำลาย ViewModel ไม่ได้ implement LifecycleOwner โดยตรง แต่สามารถรับ Lifecycle ผ่าน SavedStateHandle Navigation Component ใช้ LifecycleOwner เพื่อจัดการการสมัครรับข้อมูลใน NavBackStackEntry การเข้าใจความสัมพันธ์นี้ช่วยสร้างสถาปัตยกรรมแอปพลิเคชันบนพื้นฐานที่แข็งแกร่ง
การโต้ตอบของ LiveData กับ LifecycleOwner:
class ExampleActivity : AppCompatActivity() {
private val viewModel: ExampleViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.userData.observe(this) { data ->
// this — LifecycleOwner (Activity)
// โค้ดจะทำงานก็ต่อเมื่อ Activity อยู่ในสถานะ RESUMED
updateUI(data)
}
}
}
LiveData ต้องการ LifecycleOwner ในเมธอด observe() เนื่องจากสิ่งนี้รับประกันว่าการอัปเดต UI จะเกิดขึ้นเฉพาะในสถานะที่ทำงานอยู่เท่านั้น หาก Activity อยู่ในพื้นหลัง LiveData จะเก็บค่าล่าสุดไว้但不แจ้ง Observer เมื่อกลับสู่ RESUMED Observer จะได้รับค่าปัจจุบันโดยไม่ต้องร้องขอเครือข่ายหรือฐานข้อมูลเพิ่มเติม
DataBinding ยังใช้ LifecycleOwner เพื่อผูกฟิลด์ observable เข้ากับวงจรชีวิตของ Activity หรือ Fragment ซึ่งช่วยหลีกเลี่ยงการรั่วไหลของหน่วยความจำในการรวม ViewModel + DataBinding — การสมัครรับข้อมูลทั้งหมดจะถูกล้างโดยอัตโนมัติเมื่อ LifecycleOwner ถูกทำลาย วิธีนี้ทำให้โค้ดเป็นแบบ declarative และปลอดภัย
การใช้งาน LifecycleOwner อย่างถูกต้องต้องปฏิบัติตามกฎสำคัญหลายข้อ ข้อแรกและสำคัญที่สุด: สมัคร Observer ใน onCreate/onViewCreated เสมอ ไม่ใช่หลังจากนั้น เพื่อให้แน่ใจว่า Observer ได้รับสถานะเริ่มต้นของ Lifecycle (CREATED หลัง onCreate) และไม่พลาดเหตุการณ์ กฎข้อที่สอง: ใช้ DefaultLifecycleObserver แทนวิธีคำอธิบายประกอบสำหรับโปรเจกต์ใหม่ทั้งหมด
วิธีการสมัยใหม่ในการทำงานกับ coroutine และ LifecycleOwner — ส่วนขยาย repeatOnLifecycle:
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.flow.collect { value ->
updateUI(value)
}
}
}
รูปแบบนี้รับประกันว่า collect บน Flow จะทำงานเฉพาะในสถานะ STARTED หรือ RESUMED เมื่อเปลี่ยนเป็น STOPPED การรวบรวมจะถูกยกเลิกโดยอัตโนมัติ และเมื่อกลับสู่ STARTED จะเริ่มต้นใหม่ repeatOnLifecycle แทนที่การยกเลิกการสมัครด้วยตนเองจาก Flow ใน Fragment และเป็นวิธีการที่ Google แนะนำสำหรับการทำงานกับสตรีมข้อมูลแบบอะซิงโครนัสในคอมโพเนนต์ UI
คำแนะนำสำคัญอีกข้อ: อย่าใช้ LifecycleObserver มากเกินไป สำหรับตรรกะที่ไม่เกี่ยวข้องกับวงจรชีวิต หากคอมโพเนนต์ต้องดำเนินการในสถานะเฉพาะ但ไม่ต้องการยกเลิกการสมัครเมื่อถูกทำลาย ควรใช้การเรียกเมธอดอย่างชัดเจนใน onStart/onStop LifecycleObserver เหมาะสำหรับคอมโพเนนต์ที่มีอายุยืนยาว (LocationListener, SensorManager) ซึ่งการจัดการการสมัครด้วยตนเองซับซ้อนและมีแนวโน้มเกิดข้อผิดพลาด
คำถามที่พบบ่อย
LifecycleOwner — เป็นอินเทอร์เฟซที่ประกาศว่าอ็อบเจ็กต์มีวงจรชีวิต Lifecycle — เป็นคลาสที่จัดเก็บสถานะปัจจุบันและจัดการ Observer LifecycleOwner จัดหา Lifecycle ผ่าน getLifecycle()
ไม่ Lifecycle จะยกเลิกการสมัคร Observer ทั้งหมดโดยอัตโนมัติเมื่อเปลี่ยนเป็น DESTROYED นี่เป็นหนึ่งในข้อได้เปรียบหลักของ LifecycleOwner — นักพัฒนาไม่ต้องเรียก removeObserver ด้วยตนเองใน onDestroy
Fragment implement LifecycleOwner ผ่านอินเทอร์เฟซ fragment ของ AndroidX Lifecycle ของมันผูกกับวงจรชีวิตของ Fragment แยกจาก Activity ซึ่งช่วยให้ Observer ตอบสนองต่อเหตุการณ์ของ Fragment โดยเฉพาะ ไม่ใช่ Activity หลัก
ได้ โดยใช้ LifecycleRegistry Custom View ต้อง implement อินเทอร์เฟซ LifecycleOwner และอัปเดตสถานะของ LifecycleRegistry ด้วยตนเองเมื่อการมองเห็นหรือการแนบกับหน้าต่างเปลี่ยนไป
LifecycleOwner แก้ปัญหาที่แตกต่าง: การจัดการการสมัครรับเหตุการณ์วงจรชีวิต ไม่ใช่การยกเลิก coroutine สำหรับ coroutine ใช้ lifecycleScope ซึ่งยกเลิก coroutine ที่กำลังทำงานโดยอัตโนมัติเมื่อ LifecycleOwner ถูกทำลาย
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ