Acara Android LiveData

LiveData adalah alat yang hebat untuk menghubungkan keadaan data dan objek Anda dengan siklus hidup (LifecycleOwner, biasanya Fragmen atau Aktivitas).

Biasanya, LiveData ditempatkan di ViewModel dan digunakan untuk memperbarui keadaan UI Anda. Seringkali, ViewModel dapat bertahan dari LifecycleOwner dan mempertahankan status LiveData. Mekanisme seperti itu cocok ketika Anda perlu menyimpan data dan mengembalikannya setelah beberapa waktu, misalnya, setelah perubahan konfigurasi.

Tetapi bagaimana jika kita ingin menggunakan mekanisme peristiwa, bukan menyatakan? Dan itu perlu dalam konteks siklus hidup browser (LifecycleOwner). Misalnya, kita perlu menampilkan pesan setelah operasi asinkron, asalkan LifecycleOwner masih hidup, memiliki browser aktif, dan siap untuk memperbarui UI-nya. Jika kami menggunakan LiveData, maka kami akan menerima pesan yang sama setelah setiap perubahan konfigurasi, atau dengan setiap pelanggan baru. Salah satu solusi yang menunjukkan dirinya, setelah memproses data di beberapa browser, adalah mengatur ulang data ini ke LiveData.

Misalnya, kode seperti ini:

Observer { handle(it) yourViewModel.liveData.value = null } 

Tetapi pendekatan ini memiliki beberapa kelemahan dan tidak memenuhi semua persyaratan yang diperlukan.

Saya ingin memiliki mekanisme acara yang:

  1. hanya memberi tahu pelanggan aktif
  2. pada saat berlangganan tidak memberitahukan tentang data sebelumnya,
  3. memiliki kemampuan untuk mengatur bendera yang ditangani ke true untuk mengganggu proses lebih lanjut dari acara tersebut.

Saya menerapkan kelas MutableLiveEvent, yang memiliki semua properti di atas dan yang dapat bekerja seperti LiveData normal.

Cara menggunakan:

 //   EventArgs        class MyIntEventArgs(data: Int) : EventArgs<Int>(data) //  viewModel class MainViewModel : ViewModel() { private val myEventMutable = MutableLiveEvent<MyIntEventArgs>() val myEvent = myEventMutable as LiveData<MyIntEventArgs> fun sendEvent(data: Int) { myEventMutable.value = MyIntEventArgs(data) } } val vm = ViewModelProviders.of(this).get(MainViewModel::class.java) vm.myEvent.observe(this, Observer { //   /* *   ,    , *      ,   handled = true */ it.handled = true }) 

Semua kode tersedia di GitHub , dan di bawah ini saya akan berbicara sedikit tentang implementasinya.

 class MutableLiveEvent<T : EventArgs<Any>> : MutableLiveData<T>() { internal val observers = ArraySet<PendingObserver<in T>>() @MainThread override fun observe(owner: LifecycleOwner, observer: Observer<in T>) { val wrapper = PendingObserver(observer) observers.add(wrapper) super.observe(owner, wrapper) } override fun observeForever(observer: Observer<in T>) { val wrapper = PendingObserver(observer) observers.add(wrapper) super.observeForever(observer) } @MainThread override fun removeObserver(observer: Observer<in T>) { when (observer) { is PendingObserver -> { observers.remove(observer) super.removeObserver(observer) } else -> { val pendingObserver = observers.firstOrNull { it.wrappedObserver == observer } if (pendingObserver != null) { observers.remove(pendingObserver) super.removeObserver(pendingObserver) } } } } @MainThread override fun setValue(event: T?) { observers.forEach { it.awaitValue() } super.setValue(event) } } 

Idenya adalah bahwa di dalam kelas MutableLiveEvent, dalam metode mengamati dan mengobservasi, membungkus browser dalam kelas internal khusus PendingObserver, yang memanggil browser nyata hanya sekali dan hanya jika bendera yang tertunda disetel ke true dan acara belum diproses.

 internal class PendingObserver<T : EventArgs<Any>>(val wrappedObserver: Observer<in T>) : Observer<T> { private var pending = false override fun onChanged(event: T?) { if (pending && event?.handled != true) { pending = false wrappedObserver.onChanged(event) } } fun awaitValue() { pending = true } } 

Di PendingObserver, flag yang tertunda disetel ke false secara default. Ini menyelesaikan item 2 (jangan beri tahu data lama) dari daftar kami.

Dan kode di MutableLiveEvent

 override fun setValue(event: T?) { observers.forEach { it.awaitValue() } super.setValue(event) } 

Set pertama tertunda menjadi true dan hanya kemudian memperbarui data di dalam dirinya sendiri. Ini memastikan implementasi klaim 1. (hanya peringatan pelanggan aktif).

Poin terakhir yang belum saya bicarakan adalah EventArgs. Kelas ini adalah generalisasi di mana ada bendera yang ditangani untuk mengganggu proses lebih lanjut dari acara (Klausul 3).

 open class EventArgs<out T>(private val content: T?) { var handled: Boolean = false val data: T? get() { return if (handled) { null } else { content } } } 

Itu saja, terima kasih sudah menonton!

Source: https://habr.com/ru/post/id468749/


All Articles