ภาพรวม LiveData เป็นส่วนหนึ่งของ Android Jetpack
LiveData
เป็นคลาสที่เก็บข้อมูลแบบสังเกตได้ LiveData แตกต่างจาก Observable ทั่วไปตรงที่ LiveData จะคำนึงถึงวงจร ซึ่งหมายความว่าจะเป็นไปตามวงจรของคอมโพเนนต์อื่นๆ ของแอป เช่น กิจกรรม ฟragment หรือบริการ การตรวจสอบนี้ช่วยให้มั่นใจได้ว่า LiveData จะอัปเดตเฉพาะเครื่องมือตรวจสอบคอมโพเนนต์แอปที่อยู่ในสถานะวงจรการทํางานที่ใช้งานอยู่เท่านั้น
LiveData จะถือว่าผู้สังเกตการณ์ซึ่งแสดงโดยคลาส Observer
อยู่ในสถานะทำงานอยู่หากวงจรชีวิตของออบเซอร์เวอร์อยู่ในสถานะ STARTED
หรือ RESUMED
LiveData จะแจ้งเตือนเฉพาะผู้สังเกตการณ์ที่ใช้งานอยู่เกี่ยวกับข้อมูลอัปเดต ผู้สังเกตการณ์ที่ไม่ได้ใช้งานซึ่งลงทะเบียนเพื่อดูออบเจ็กต์ LiveData
จะไม่ได้รับการแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลง
คุณสามารถลงทะเบียนผู้สังเกตการณ์ที่จับคู่กับออบเจ็กต์ที่ใช้LifecycleOwner
อินเทอร์เฟซ ความสัมพันธ์นี้ช่วยให้นำเครื่องมือตรวจสอบออกได้เมื่อสถานะของออบเจ็กต์ Lifecycle
ที่เกี่ยวข้องเปลี่ยนไปเป็น DESTROYED
ซึ่งจะเป็นประโยชน์อย่างยิ่งสําหรับกิจกรรมและข้อมูลโค้ดที่ฝังอยู่ เนื่องจากสามารถสังเกตออบเจ็กต์ LiveData
ได้อย่างปลอดภัยและไม่ต้องกังวลเกี่ยวกับการรั่วไหล เนื่องจากระบบจะยกเลิกการติดตามกิจกรรมและข้อมูลโค้ดที่ฝังอยู่ทันทีเมื่อทำลายวงจรชีวิตของออบเจ็กต์
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้ LiveData ได้ที่ทํางานกับออบเจ็กต์ LiveData
ข้อดีของการใช้ LiveData
การใช้ LiveData มีข้อดีดังนี้
- ตรวจสอบว่า UI ตรงกับสถานะข้อมูล
- LiveData เป็นไปตามรูปแบบการสังเกตการณ์ LiveData จะแจ้งเตือนออบเจ็กต์
Observer
เมื่อข้อมูลพื้นฐานมีการเปลี่ยนแปลง คุณสามารถรวมโค้ดเพื่ออัปเดต UI ในออบเจ็กต์Observer
เหล่านี้ได้ วิธีนี้จะช่วยให้คุณไม่ต้องอัปเดต UI ทุกครั้งที่ข้อมูลแอปมีการเปลี่ยนแปลง เนื่องจากเครื่องมือสังเกตการณ์จะอัปเดตให้คุณ - ไม่มีการรั่วไหลของหน่วยความจำ
- ออบเซอร์เวอร์จะเชื่อมโยงกับออบเจ็กต์
Lifecycle
และล้างข้อมูลของตนเองเมื่อวงจรที่เกี่ยวข้องถูกทำลาย - ไม่มีการขัดข้องเนื่องจากกิจกรรมที่หยุดลง
- หากวงจรชีวิตของผู้สังเกตไม่ทำงาน เช่น ในกรณีของกิจกรรมในกองซ้อนด้านหลัง ผู้สังเกตจะไม่ได้รับการแจ้งเตือนเหตุการณ์ LiveData
- ไม่ต้องจัดการวงจรด้วยตนเองอีกต่อไป
- คอมโพเนนต์ UI จะสังเกตเฉพาะข้อมูลที่เกี่ยวข้องเท่านั้น โดยไม่หยุดหรือกลับมาสังเกตต่อ LiveData จะจัดการข้อมูลทั้งหมดนี้โดยอัตโนมัติเนื่องจากทราบถึงการเปลี่ยนแปลงสถานะวงจรที่เกี่ยวข้องขณะสังเกตการณ์
- ข้อมูลล่าสุดอยู่เสมอ
- หากวงจรของลูกค้าไม่ทำงาน วงจรดังกล่าวจะได้รับข้อมูลล่าสุดเมื่อกลับมาทำงานอีกครั้ง เช่น กิจกรรมที่อยู่ในเบื้องหลังจะได้รับข้อมูลล่าสุดทันทีที่กลับมาอยู่เบื้องหน้า
- การเปลี่ยนแปลงการกําหนดค่าที่เหมาะสม
- หากมีการสร้างกิจกรรมหรือข้อมูลโค้ดอีกรอบเนื่องจากการเปลี่ยนแปลงการกําหนดค่า เช่น การพลิกอุปกรณ์ กิจกรรมหรือข้อมูลโค้ดนั้นจะรับข้อมูลล่าสุดที่มีอยู่ทันที
- การแชร์ทรัพยากร
- คุณสามารถขยายออบเจ็กต์
LiveData
โดยใช้รูปแบบ Singleton เพื่อรวมบริการของระบบเพื่อให้แชร์ในแอปได้ ออบเจ็กต์LiveData
จะเชื่อมต่อกับบริการของระบบเพียงครั้งเดียว จากนั้นผู้สังเกตการณ์ที่ต้องการทรัพยากรก็สามารถดูออบเจ็กต์LiveData
ได้ ดูข้อมูลเพิ่มเติมได้ที่ขยาย LiveData
ทำงานกับออบเจ็กต์ LiveData
ทําตามขั้นตอนต่อไปนี้เพื่อทํางานกับออบเจ็กต์ LiveData
- สร้างอินสแตนซ์ของ
LiveData
เพื่อเก็บข้อมูลบางประเภท ซึ่งโดยปกติจะดำเนินการภายในชั้นเรียนViewModel
- สร้างออบเจ็กต์
Observer
ที่กําหนดวิธีonChanged()
ซึ่งควบคุมสิ่งที่จะเกิดขึ้นเมื่อข้อมูลที่มีของออบเจ็กต์LiveData
เปลี่ยนแปลง โดยปกติแล้ว คุณจะต้องสร้างออบเจ็กต์Observer
ในตัวควบคุม UI เช่น กิจกรรมหรือแฟรกเมนต์ แนบออบเจ็กต์
Observer
กับออบเจ็กต์LiveData
โดยใช้เมธอดobserve()
เมธอดobserve()
ใช้ออบเจ็กต์LifecycleOwner
ซึ่งจะสมัครรับข้อมูลออบเจ็กต์Observer
กับออบเจ็กต์LiveData
เพื่อให้ได้รับการแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลง โดยปกติแล้วคุณจะแนบออบเจ็กต์Observer
ในตัวควบคุม UI เช่น กิจกรรมหรือแฟรกเมนต์
เมื่อคุณอัปเดตค่าที่จัดเก็บไว้ในออบเจ็กต์ LiveData
ระบบจะทริกเกอร์ผู้สังเกตการณ์ที่ลงทะเบียนไว้ทั้งหมด ตราบใดที่ LifecycleOwner
ที่แนบมาอยู่ในสถานะ "ทำงานอยู่"
LiveData ช่วยให้ผู้สังเกตการณ์ตัวควบคุม UI สามารถติดตามการอัปเดตได้ เมื่อข้อมูลที่อยู่ในออบเจ็กต์ LiveData
มีการเปลี่ยนแปลง UI จะอัปเดตโดยอัตโนมัติเพื่อตอบสนอง
สร้างออบเจ็กต์ LiveData
LiveData คือ Wrapper ที่ใช้กับข้อมูลใดก็ได้ รวมถึงออบเจ็กต์ที่ใช้ Collections
เช่น List
โดยปกติแล้วออบเจ็กต์ LiveData
จะเก็บไว้ในออบเจ็กต์ ViewModel
และเข้าถึงผ่านเมธอด getter ดังที่แสดงในตัวอย่างต่อไปนี้
Kotlin
class NameViewModel : ViewModel() { // Create a LiveData with a String val currentName: MutableLiveData<String> by lazy { MutableLiveData<String>() } // Rest of the ViewModel... }
Java
public class NameViewModel extends ViewModel { // Create a LiveData with a String private MutableLiveData<String> currentName; public MutableLiveData<String> getCurrentName() { if (currentName == null) { currentName = new MutableLiveData<String>(); } return currentName; } // Rest of the ViewModel... }
ในช่วงแรก จะไม่มีการตั้งค่าข้อมูลในออบเจ็กต์ LiveData
อ่านข้อมูลเพิ่มเติมเกี่ยวกับประโยชน์และการใช้งานของคลาส ViewModel
ได้ในคู่มือ ViewModel
สังเกตออบเจ็กต์ LiveData
ในกรณีส่วนใหญ่ วิธีการ onCreate()
ของคอมโพเนนต์แอปคือจุดเริ่มต้นที่เหมาะสมในการสังเกตออบเจ็กต์ LiveData
ด้วยเหตุผลต่อไปนี้
- เพื่อให้ระบบไม่เรียกใช้จากเมธอด
onResume()
ของกิจกรรมหรือส่วนที่ซ้ำกัน - เพื่อให้กิจกรรมหรือข้อมูลโค้ดมีข้อมูลที่แสดงได้ทันทีที่เริ่มทำงาน ทันทีที่คําประกอบแอปอยู่ในสถานะ
STARTED
คอมโพเนนต์ดังกล่าวจะได้รับค่าล่าสุดจากออบเจ็กต์LiveData
ที่กำลังสังเกตอยู่ กรณีนี้จะเกิดขึ้นก็ต่อเมื่อมีการตั้งค่าออบเจ็กต์LiveData
ที่จะสังเกตเท่านั้น
โดยทั่วไป LiveData จะส่งการอัปเดตเฉพาะเมื่อมีการเปลี่ยนแปลงข้อมูล และส่งไปยังผู้สังเกตการณ์ที่ใช้งานอยู่เท่านั้น ข้อยกเว้นของลักษณะการทํางานนี้คือ ผู้สังเกตการณ์จะได้รับข้อมูลอัปเดตด้วยเมื่อเปลี่ยนจากสถานะ "ไม่ได้ใช้งาน" เป็น "ใช้งานอยู่" นอกจากนี้ หากเครื่องมือตรวจสอบเปลี่ยนจาก "ไม่ทำงาน" เป็น "ทำงานอยู่" เป็นครั้งที่ 2 เครื่องมือจะได้รับการอัปเดตก็ต่อเมื่อค่ามีการเปลี่ยนแปลงนับตั้งแต่ที่ทำงานอยู่ครั้งล่าสุด
โค้ดตัวอย่างต่อไปนี้แสดงวิธีเริ่มสังเกตการณ์LiveData
ออบเจ็กต์
Kotlin
class NameActivity : AppCompatActivity() { // Use the 'by viewModels()' Kotlin property delegate // from the activity-ktx artifact private val model: NameViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Other code to setup the activity... // Create the observer which updates the UI. val nameObserver = Observer<String> { newName -> // Update the UI, in this case, a TextView. nameTextView.text = newName } // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer. model.currentName.observe(this, nameObserver) } }
Java
public class NameActivity extends AppCompatActivity { private NameViewModel model; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Other code to setup the activity... // Get the ViewModel. model = new ViewModelProvider(this).get(NameViewModel.class); // Create the observer which updates the UI. final Observer<String> nameObserver = new Observer<String>() { @Override public void onChanged(@Nullable final String newName) { // Update the UI, in this case, a TextView. nameTextView.setText(newName); } }; // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer. model.getCurrentName().observe(this, nameObserver); } }
หลังจากเรียกใช้ observe()
โดยส่ง nameObserver
เป็นพารามิเตอร์แล้ว ระบบจะเรียกใช้ onChanged()
ทันทีพร้อมระบุค่าล่าสุดที่จัดเก็บไว้ใน mCurrentName
หากออบเจ็กต์ LiveData
ไม่ได้ตั้งค่าใน mCurrentName
ระบบจะไม่เรียกใช้ onChanged()
อัปเดตออบเจ็กต์ LiveData
LiveData ไม่มีวิธีการที่เผยแพร่ต่อสาธารณะเพื่ออัปเดตข้อมูลที่จัดเก็บไว้ คลาส MutableLiveData
แสดงเมธอด setValue(T)
และ postValue(T)
แก่สาธารณะ และคุณต้องใช้เมธอดเหล่านี้หากต้องการแก้ไขค่าที่เก็บไว้ในออบเจ็กต์ LiveData
โดยปกติแล้ว MutableLiveData
จะใช้ใน ViewModel
จากนั้น ViewModel
จะแสดงเฉพาะออบเจ็กต์ LiveData
ที่ไม่เปลี่ยนแปลงได้ต่อผู้สังเกตการณ์
หลังจากตั้งค่าความสัมพันธ์ของผู้สังเกตการณ์แล้ว คุณจะอัปเดตค่าของออบเจ็กต์ LiveData
ได้ ดังที่แสดงในตัวอย่างต่อไปนี้ ซึ่งจะทริกเกอร์ผู้สังเกตการณ์ทั้งหมดเมื่อผู้ใช้แตะปุ่ม
Kotlin
button.setOnClickListener { val anotherName = "John Doe" model.currentName.setValue(anotherName) }
Java
button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String anotherName = "John Doe"; model.getCurrentName().setValue(anotherName); } });
การเรียก setValue(T)
ในตัวอย่างนี้ส่งผลให้ผู้สังเกตการณ์เรียกใช้เมธอด onChanged()
ด้วยค่า John Doe
ตัวอย่างนี้แสดงการกดปุ่ม แต่อาจเรียก setValue()
หรือ postValue()
เพื่ออัปเดต mName
ด้วยเหตุผลหลายประการ ซึ่งรวมถึงการตอบสนองต่อคําขอเครือข่ายหรือการโหลดฐานข้อมูลที่เสร็จสมบูรณ์ ในทุกกรณี การเรียก setValue()
หรือ postValue()
จะทริกเกอร์ผู้สังเกตการณ์และอัปเดต UI
ใช้ LiveData กับ Room
ไลบรารีการคงข้อมูล Room รองรับการค้นหาที่สังเกตได้ ซึ่งจะแสดงผลออบเจ็กต์ LiveData
การค้นหาที่สังเกตได้จะเขียนขึ้นเป็นส่วนหนึ่งของออบเจ็กต์การเข้าถึงฐานข้อมูล (DAO)
Room จะสร้างโค้ดที่จำเป็นทั้งหมดเพื่ออัปเดตออบเจ็กต์ LiveData
เมื่ออัปเดตฐานข้อมูล โค้ดที่สร้างขึ้นจะเรียกใช้การค้นหาแบบอะซิงโครนัสในเธรดเบื้องหลังเมื่อจำเป็น รูปแบบนี้มีประโยชน์ในการทำให้ข้อมูลที่แสดงใน UI ซิงค์กับข้อมูลที่จัดเก็บไว้ในฐานข้อมูล อ่านข้อมูลเพิ่มเติมเกี่ยวกับ Room และ DAO ได้ในคู่มือคลังถาวรของ Room
ใช้ Coroutine กับ LiveData
LiveData
รองรับโคโริวทีนของ Kotlin ดูข้อมูลเพิ่มเติมได้ที่หัวข้อใช้โคโริวทีนของ Kotlin กับคอมโพเนนต์สถาปัตยกรรม Android
LiveData ในสถาปัตยกรรมของแอป
LiveData
รับรู้วงจรของข้อมูลต่างๆ เช่น กิจกรรมและข้อมูล ใช้ LiveData
เพื่อสื่อสารระหว่างเจ้าของวงจรเหล่านี้กับออบเจ็กต์อื่นๆ ที่มีอายุการใช้งานต่างกัน เช่น ออบเจ็กต์ ViewModel
หน้าที่หลักของ ViewModel
คือโหลดและจัดการข้อมูลที่เกี่ยวข้องกับ UI ซึ่งทำให้เหมาะอย่างยิ่งที่จะเก็บออบเจ็กต์ LiveData
สร้างออบเจ็กต์ LiveData
ใน ViewModel
และใช้เพื่อแสดงสถานะต่อเลเยอร์ UI
กิจกรรมและฟragment ไม่ควรเก็บอินสแตนซ์ LiveData
เนื่องจากบทบาทของกิจกรรมและฟragment คือการแสดงข้อมูล ไม่ใช่เก็บสถานะ นอกจากนี้ การที่กิจกรรมและฟragment ไม่มีการถือครองข้อมูลยังช่วยให้เขียนการทดสอบหน่วยได้ง่ายขึ้นด้วย
คุณอาจต้องการใช้ออบเจ็กต์ LiveData
ในคลาสเลเยอร์ข้อมูล แต่ LiveData
ไม่ได้ออกแบบมาเพื่อจัดการสตรีมข้อมูลที่ทำงานแบบไม่พร้อมกัน แม้ว่าคุณจะใช้การเปลี่ยนรูปแบบ LiveData
และ MediatorLiveData
ได้เพื่อดำเนินการนี้ แต่วิธีการนี้มีข้อเสียคือความสามารถในการรวมสตรีมข้อมูลมีขีดจํากัดมาก และระบบจะสังเกตออบเจ็กต์ LiveData
ทั้งหมด (รวมถึงออบเจ็กต์ที่สร้างผ่านการเปลี่ยนรูปแบบ) ในเธรดหลัก โค้ดด้านล่างเป็นตัวอย่างการกด LiveData
ใน Repository
เพื่อบล็อกชุดข้อความหลัก
Kotlin
class UserRepository { // DON'T DO THIS! LiveData objects should not live in the repository. fun getUsers(): LiveData<List<User>> { ... } fun getNewPremiumUsers(): LiveData<List<User>> { return getUsers().map { users -> // This is an expensive call being made on the main thread and may // cause noticeable jank in the UI! users .filter { user -> user.isPremium } .filter { user -> val lastSyncedTime = dao.getLastSyncedTime() user.timeCreated > lastSyncedTime } } }
Java
class UserRepository { // DON'T DO THIS! LiveData objects should not live in the repository. LiveData<List<User>> getUsers() { ... } LiveData<List<User>> getNewPremiumUsers() { return Transformations.map(getUsers(), // This is an expensive call being made on the main thread and may cause // noticeable jank in the UI! users -> users.stream() .filter(User::isPremium) .filter(user -> user.getTimeCreated() > dao.getLastSyncedTime()) .collect(Collectors.toList())); } }
หากต้องการใช้สตรีมข้อมูลในเลเยอร์อื่นๆ ของแอป ให้พิจารณาใช้ Kotlin Flow แล้วแปลงเป็น LiveData
ใน ViewModel
โดยใช้ asLiveData()
ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ Kotlin Flow
กับ LiveData
ใน Codelab นี้
สําหรับโค้ดเบสที่สร้างด้วย Java ให้ลองใช้ Executor ร่วมกับการเรียกกลับหรือ RxJava
ขยาย LiveData
LiveData จะถือว่าผู้สังเกตการณ์อยู่ในสถานะ "ใช้งานอยู่" หากวงจรชีวิตของผู้สังเกตการณ์อยู่ในสถานะ STARTED
หรือ RESUMED
โค้ดตัวอย่างต่อไปนี้แสดงวิธีขยายคลาส LiveData
Kotlin
class StockLiveData(symbol: String) : LiveData<BigDecimal>() { private val stockManager = StockManager(symbol) private val listener = { price: BigDecimal -> value = price } override fun onActive() { stockManager.requestPriceUpdates(listener) } override fun onInactive() { stockManager.removeUpdates(listener) } }
Java
public class StockLiveData extends LiveData<BigDecimal> { private StockManager stockManager; private SimplePriceListener listener = new SimplePriceListener() { @Override public void onPriceChanged(BigDecimal price) { setValue(price); } }; public StockLiveData(String symbol) { stockManager = new StockManager(symbol); } @Override protected void onActive() { stockManager.requestPriceUpdates(listener); } @Override protected void onInactive() { stockManager.removeUpdates(listener); } }
การติดตั้งใช้งานเครื่องมือรับฟังราคาในตัวอย่างนี้ประกอบด้วยเมธอดที่สําคัญต่อไปนี้
- ระบบจะเรียกใช้เมธอด
onActive()
เมื่อออบเจ็กต์LiveData
มีผู้สังเกตที่ใช้งานอยู่ ซึ่งหมายความว่าคุณต้องเริ่มสังเกตการอัปเดตราคาหุ้นจากวิธีการนี้ - ระบบจะเรียกใช้เมธอด
onInactive()
เมื่อออบเจ็กต์LiveData
ไม่มีผู้สังเกตการณ์ที่ทำงานอยู่ เนื่องจากไม่มีผู้สังเกตการณ์ฟังอยู่ จึงไม่มีเหตุผลที่จะเชื่อมต่อกับบริการStockManager
ต่อไป - เมธอด
setValue(T)
จะอัปเดตค่าของอินสแตนซ์LiveData
และแจ้งให้ออบเซอร์เวอร์ที่ใช้งานอยู่ทราบเกี่ยวกับการเปลี่ยนแปลง
คุณใช้คลาส StockLiveData
ได้ดังนี้
Kotlin
public class MyFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val myPriceListener: LiveData<BigDecimal> = ... myPriceListener.observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? -> // Update the UI. }) } }
Java
public class MyFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); LiveData<BigDecimal> myPriceListener = ...; myPriceListener.observe(getViewLifecycleOwner(), price -> { // Update the UI. }); } }
วิธีการจะส่ง LifecycleOwner
ที่เชื่อมโยงกับมุมมองของข้อมูลโค้ดเป็นอาร์กิวเมนต์แรกobserve()
ซึ่งหมายความว่าตัวสังเกตการณ์นี้เชื่อมโยงกับออบเจ็กต์ Lifecycle
ที่เชื่อมโยงกับเจ้าของ
- หากออบเจ็กต์
Lifecycle
ไม่ได้อยู่ในสถานะ "ใช้งานอยู่" ระบบจะไม่เรียกใช้ออบเซอร์เวอร์แม้ว่าค่าจะเปลี่ยนแปลงก็ตาม - หลังจากทำลายออบเจ็กต์
Lifecycle
แล้ว ระบบจะนำเครื่องมือตรวจสอบออกโดยอัตโนมัติ
การที่ออบเจ็กต์ LiveData
รับรู้ถึงวงจรของวัตถุหมายความว่าคุณสามารถแชร์ออบเจ็กต์เหล่านั้นระหว่างกิจกรรม ฟragment และบริการหลายรายการได้ หากต้องการให้ตัวอย่างเข้าใจง่าย คุณสามารถติดตั้งใช้งานคลาส LiveData
เป็น Singleton ดังนี้
Kotlin
class StockLiveData(symbol: String) : LiveData<BigDecimal>() { private val stockManager: StockManager = StockManager(symbol) private val listener = { price: BigDecimal -> value = price } override fun onActive() { stockManager.requestPriceUpdates(listener) } override fun onInactive() { stockManager.removeUpdates(listener) } companion object { private lateinit var sInstance: StockLiveData @MainThread fun get(symbol: String): StockLiveData { sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol) return sInstance } } }
Java
public class StockLiveData extends LiveData<BigDecimal> { private static StockLiveData sInstance; private StockManager stockManager; private SimplePriceListener listener = new SimplePriceListener() { @Override public void onPriceChanged(BigDecimal price) { setValue(price); } }; @MainThread public static StockLiveData get(String symbol) { if (sInstance == null) { sInstance = new StockLiveData(symbol); } return sInstance; } private StockLiveData(String symbol) { stockManager = new StockManager(symbol); } @Override protected void onActive() { stockManager.requestPriceUpdates(listener); } @Override protected void onInactive() { stockManager.removeUpdates(listener); } }
และคุณใช้ข้อมูลดังกล่าวในข้อมูลโค้ดต่อไปนี้ได้
Kotlin
class MyFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? -> // Update the UI. }) }
Java
public class MyFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> { // Update the UI. }); } }
หลายรายการย่อยและกิจกรรมสามารถสังเกตอินสแตนซ์ MyPriceListener
ได้
LiveData จะเชื่อมต่อกับบริการของระบบก็ต่อเมื่อมีบริการอย่างน้อย 1 รายการที่มองเห็นได้และใช้งานอยู่
เปลี่ยนรูปแบบ LiveData
คุณอาจต้องเปลี่ยนแปลงค่าที่จัดเก็บไว้ในออบเจ็กต์ LiveData
ก่อนส่งไปยังผู้สังเกตการณ์ หรืออาจต้องแสดงผลอินสแตนซ์ LiveData
อื่นโดยอิงตามค่าของอินสแตนซ์อื่น แพ็กเกจ Lifecycle
มีคลาส Transformations
ที่มีเมธอดตัวช่วยที่รองรับสถานการณ์เหล่านี้
Transformations.map()
- ใช้ฟังก์ชันกับค่าที่เก็บไว้ในออบเจ็กต์
LiveData
และเผยแพร่ผลลัพธ์ลงไปยังส่วนปลาย
Kotlin
val userLiveData: LiveData<User> = UserLiveData() val userName: LiveData<String> = userLiveData.map { user -> "${user.name} ${user.lastName}" }
Java
LiveData<User> userLiveData = ...; LiveData<String> userName = Transformations.map(userLiveData, user -> { user.name + " " + user.lastName });
Transformations.switchMap()
- คล้ายกับ
map()
จะใช้ฟังก์ชันกับค่าที่จัดเก็บไว้ในออบเจ็กต์LiveData
และแยกออกและส่งผลลัพธ์ไป downstream ฟังก์ชันที่ส่งผ่านไปยังswitchMap()
จะต้องแสดงผลออบเจ็กต์LiveData
ดังที่แสดงในตัวอย่างต่อไปนี้
Kotlin
private fun getUser(id: String): LiveData<User> { ... } val userId: LiveData<String> = ... val user = userId.switchMap { id -> getUser(id) }
Java
private LiveData<User> getUser(String id) { ...; } LiveData<String> userId = ...; LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
คุณสามารถใช้เมธอดการเปลี่ยนรูปแบบเพื่อส่งข้อมูลตลอดวงจรชีวิตของผู้สังเกตการณ์ ระบบจะไม่คํานวณการเปลี่ยนรูปแบบ เว้นแต่ผู้สังเกตการณ์จะดูออบเจ็กต์ LiveData
ที่แสดงผล เนื่องจากระบบจะคำนวณการเปลี่ยนรูปแบบแบบเลื่อนลอย ระบบจึงจะส่งต่อลักษณะการทำงานที่เกี่ยวข้องกับวงจรแบบนัยโดยไม่จำเป็นต้องมีการเรียกใช้หรือข้อกําหนดเพิ่มเติมอย่างชัดเจน
หากคุณคิดว่าจําเป็นต้องใช้ออบเจ็กต์ Lifecycle
ภายในออบเจ็กต์ ViewModel
การเปลี่ยนรูปแบบอาจเป็นวิธีแก้ปัญหาที่ดีกว่า ตัวอย่างเช่น สมมติว่าคุณมีคอมโพเนนต์ UI ที่ยอมรับที่อยู่และแสดงผลรหัสไปรษณีย์ของที่อยู่นั้น คุณสามารถใช้ ViewModel
แบบไม่ซับซ้อนสําหรับคอมโพเนนต์นี้ได้ ดังที่แสดงในโค้ดตัวอย่างต่อไปนี้
Kotlin
class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() { private fun getPostalCode(address: String): LiveData<String> { // DON'T DO THIS return repository.getPostCode(address) } }
Java
class MyViewModel extends ViewModel { private final PostalCodeRepository repository; public MyViewModel(PostalCodeRepository repository) { this.repository = repository; } private LiveData<String> getPostalCode(String address) { // DON'T DO THIS return repository.getPostCode(address); } }
จากนั้นคอมโพเนนต์ UI จะต้องยกเลิกการลงทะเบียนจากออบเจ็กต์ LiveData
ก่อนหน้า และลงทะเบียนกับอินสแตนซ์ใหม่ทุกครั้งที่เรียกใช้ getPostalCode()
นอกจากนี้ หากสร้างคอมโพเนนต์ UI ขึ้นมาใหม่ ระบบจะเรียกใช้เมธอด repository.getPostCode()
อีกครั้งแทนที่จะใช้ผลลัพธ์ของการเรียกใช้ก่อนหน้านี้
แต่คุณใช้การค้นหารหัสไปรษณีย์เป็นการแปลงอินพุตที่อยู่ได้ ดังที่แสดงในตัวอย่างต่อไปนี้
Kotlin
class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() { private val addressInput = MutableLiveData<String>() val postalCode: LiveData<String> = addressInput.switchMap { address -> repository.getPostCode(address) } private fun setInput(address: String) { addressInput.value = address } }
Java
class MyViewModel extends ViewModel { private final PostalCodeRepository repository; private final MutableLiveData<String> addressInput = new MutableLiveData(); public final LiveData<String> postalCode = Transformations.switchMap(addressInput, (address) -> { return repository.getPostCode(address); }); public MyViewModel(PostalCodeRepository repository) { this.repository = repository } private void setInput(String address) { addressInput.setValue(address); } }
ในกรณีนี้ ระบบจะกําหนดฟิลด์ postalCode
เป็นการเปลี่ยนรูปแบบของ
addressInput
ตราบใดที่แอปของคุณมีผู้สังเกตการณ์ที่ใช้งานอยู่ซึ่งเชื่อมโยงกับช่อง postalCode
ระบบจะคํานวณค่าของช่องใหม่และดึงข้อมูลทุกครั้งที่ postalCode
มีการเปลี่ยนแปลงaddressInput
กลไกนี้ช่วยให้แอปในระดับที่ต่ำกว่าสร้างออบเจ็กต์ LiveData
ที่คำนวณแบบล่าช้าตามคําขอได้ ออบเจ็กต์ ViewModel
สามารถรับการอ้างอิงออบเจ็กต์ LiveData
ได้อย่างง่ายดาย จากนั้นจึงกำหนดกฎการเปลี่ยนรูปแบบเพิ่มเติม
สร้างการเปลี่ยนรูปแบบใหม่
การเปลี่ยนรูปแบบที่เฉพาะเจาะจงหลายสิบรายการอาจมีประโยชน์ในแอป แต่ระบบไม่ได้ระบุไว้โดยค่าเริ่มต้น หากต้องการใช้การเปลี่ยนรูปแบบของคุณเอง คุณสามารถใช้คลาส MediatorLiveData
ซึ่งจะคอยฟังออบเจ็กต์ LiveData
อื่นๆ และประมวลผลเหตุการณ์ที่ออบเจ็กต์เหล่านั้นส่งออกมา MediatorLiveData
เผยแพร่สถานะไปยังออบเจ็กต์ LiveData
ต้นทางอย่างถูกต้อง ดูข้อมูลเพิ่มเติมเกี่ยวกับรูปแบบนี้ได้ในเอกสารอ้างอิงของคลาส Transformations
ผสานแหล่งที่มาของ LiveData หลายแหล่ง
MediatorLiveData
เป็นคลาสย่อยของ LiveData
ซึ่งช่วยให้คุณผสานแหล่งข้อมูล LiveData หลายแหล่งได้ จากนั้นตัวสังเกตการณ์ของMediatorLiveData
ออบเจ็กต์จะทริกเกอร์เมื่อใดก็ตามที่ออบเจ็กต์แหล่งที่มาของ LiveData เดิมมีการเปลี่ยนแปลง
เช่น หากคุณมีออบเจ็กต์ LiveData
ใน UI ที่อัปเดตได้จากฐานข้อมูลในเครื่องหรือเครือข่าย คุณสามารถเพิ่มแหล่งที่มาต่อไปนี้ลงในออบเจ็กต์ MediatorLiveData
ได้
- ออบเจ็กต์
LiveData
ที่เชื่อมโยงกับข้อมูลที่จัดเก็บไว้ในฐานข้อมูล - ออบเจ็กต์
LiveData
ที่เชื่อมโยงกับข้อมูลที่เข้าถึงจากเครือข่าย
กิจกรรมของคุณต้องสังเกตออบเจ็กต์ MediatorLiveData
เท่านั้นเพื่อรับการอัปเดตจากทั้ง 2 แหล่ง ดูตัวอย่างโดยละเอียดได้ที่ส่วนภาคผนวก: การเปิดเผยสถานะเครือข่ายในคู่มือเกี่ยวกับสถาปัตยกรรมแอป
แหล่งข้อมูลเพิ่มเติม
หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับคลาส LiveData
โปรดดูแหล่งข้อมูลต่อไปนี้
ตัวอย่าง
- Sunflower เป็นแอปสาธิตที่แสดงแนวทางปฏิบัติแนะนำเกี่ยวกับคอมโพเนนต์สถาปัตยกรรม
Codelabs
- Android Room ที่มี View (Java) (Kotlin)
- ดู Coroutines ขั้นสูงด้วย Kotlin Flow และ LiveData
บล็อก
- ViewModel และ LiveData: รูปแบบและรูปแบบที่ไม่แนะนำ
- LiveData นอกเหนือจาก ViewModel - รูปแบบการตอบสนองโดยใช้การเปลี่ยนรูปแบบและ MediatorLiveData
- LiveData ที่มี SnackBar, การนําทาง และเหตุการณ์อื่นๆ (กรณี SingleLiveEvent)
วิดีโอ
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ใช้โคโริวทีนของ Kotlin กับคอมโพเนนต์ที่รู้เกี่ยวกับวงจร
- การจัดการวงจรด้วยคอมโพเนนต์ที่รับรู้วงจร
- ทดสอบการใช้งานการแบ่งหน้า