ViewModel'den Canlı Verileri Gözlemleme


95

Veri getirmeyi (özellikle Firebase) yönettiğim ayrı bir sınıfım var ve genellikle ondan LiveData nesnelerini döndürüp eşzamansız olarak güncelliyorum. Şimdi döndürülen verilerin bir ViewModel'de depolanmasını istiyorum, ancak sorun şu ki, söz konusu değeri elde etmek için, veri alma sınıfımdan döndürülen LiveData nesnesini gözlemlemem gerekiyor. Gözlem yöntemi, ilk parametre olarak bir LifecycleOwner nesnesi gerektiriyordu, ancak açıkçası ViewModel'imin içinde buna sahip değilim ve ViewModel'in içindeki Activity / Fragment'a bir referans tutmamam gerektiğini biliyorum. Ne yapmalıyım?


Yanıtlar:


39

Gelen bu blog yayınında Google geliştirici Jose Alcerreca tarafından nedeniyle (paragrafında "Depoda LiveData" bölümüne bakınız) bu durumda bir dönüşüm kullanılması önerilir ViewModel ilişkin herhangi bir referans tutmamalı Viewzor yaptım çünkü (Etkinlik, vb Bağlam) test etmek için.


Dönüşümün sizin için çalışmasını sağladınız mı? Etkinliklerim çalışmıyor
romaneso

26
Dönüşümler kendi başlarına çalışmaz, çünkü dönüşümde yazdığınız kod yalnızca bazı varlık dönüşümü gözlemlediğinde çalıştırılmak üzere eklenir .
orbitbot

9
Bunun neden önerilen cevap olduğunu bilmiyorum, soruyla hiçbir ilgisi yok. 2 yıl sonra ve hala görünüm modelimizde depo veri değişikliklerini nasıl gözlemleyeceğimizi bilmiyoruz.
Andrew

26

In ViewModel belgelerinde

Ancak ViewModel nesneleri, LiveData nesneleri gibi yaşam döngüsüne duyarlı gözlemlenebilir öğelerdeki değişiklikleri asla gözlemlememelidir.

Başka bir yol, verilerin LiveData yerine RxJava'yı uygulamasıdır, o zaman yaşam döngüsüne duyarlı olma avantajına sahip olmayacaktır.

Todo-mvvm-live-kotlin'in google örneğinde, ViewModel'de LiveData olmadan bir geri arama kullanır.

Yaşam döngüsü yazılımı olma fikrinin tamamına uymak istiyorsanız, gözlem kodunu Activity / Fragment'a taşımamız gerektiğini tahmin ediyorum. Aksi takdirde, ViewModel'de geri arama veya RxJava kullanabiliriz.

Diğer bir uzlaşma ise MediatorLiveData'yı (veya Dönüşümleri) uygulamak ve ViewModel'de gözlemlemek (mantığınızı buraya koyun). Dikkat, MediatorLiveData gözlemcisi, Activity / Fragment'te gözlenmediği sürece tetiklenmez (Dönüşümler ile aynı). Gerçek işin aslında ViewModel'de yapıldığı Activity / Fragment'e boş bir gözlem koyuyoruz.

// ViewModel
fun start(id : Long) : LiveData<User>? {
    val liveData = MediatorLiveData<User>()
    liveData.addSource(dataSource.getById(id), Observer {
        if (it != null) {
            // put your logic here
        }
    })
}

// Activity/Fragment
viewModel.start(id)?.observe(this, Observer {
    // blank observe here
})

Not: ViewModels ve LiveData: Patterns + AntiPatterns okudum ki bu Transformations önerdi. LiveData gözlemlenmedikçe çalıştığını sanmıyorum (muhtemelen Activity / Fragment'de yapılmasını gerektirir).


2
Bu konuda bir değişiklik oldu mu? Veya RX, geri arama veya boş gözlem sadece çözüm mü?
qbait

2
Bu boş gözlemlerden kurtulmak için herhangi bir çözüm var mı?
Ehsan Mashhadi

1
Belki Flow ( mLiveData.asFlow()) veya observeForever.
Machado

Fragment'te istemiyorsanız / herhangi bir gözlemci mantığına ihtiyacınız yoksa akış çözümü işe yarıyor gibi görünüyor
adek111

14

Yaşam döngüsü sahibi arayüzünü gerektirmeyen observeForever'ı kullanabileceğinizi ve görünüm modelinden sonuçları gözlemleyebileceğinizi düşünüyorum.


2
bu bana özellikle de ViewModel.onCleared () ile ilgili belgelerde şöyle söylendiğinde doğru cevap gibi görünüyor: "ViewModel bazı verileri gözlemlediğinde yararlıdır ve bu ViewModel'in sızmasını önlemek için bu aboneliği temizlemeniz gerekir."
Yosef

2
Üzgünüm amaCannot invoke observeForever on a background thread
Boken

1
Bu oldukça meşru görünüyor. ViewModel alanlarında gözlemcileri kaydetmeli ve adresinden aboneliğinizi iptal etmelisiniz onCleared. Arka plan iş parçacığına gelince - ana iş parçacığından gözlemleyin, hepsi bu.
Kirill Starostin

@Boken observeForeverAna GlobalScope.launch(Dispatchers.Main) { myvm.observeForever() }
kanaldan

5

Mimari bileşenler ile Kotlin eşgüdümlerini kullanın.

Sen kullanabilirsiniz liveDatabir aramaya oluşturucu işlevi suspendbir şekilde sonuca hizmet eden, fonksiyonunu LiveDatanesne.

val user: LiveData<User> = liveData {
    val data = database.loadUser() // loadUser is a suspend function.
    emit(data)
}

Ayrıca bloktan birden fazla değer gönderebilirsiniz. Her emit()çağrı, LiveDatadeğer ana iş parçacığında ayarlanana kadar bloğun yürütülmesini askıya alır .

val user: LiveData<Result> = liveData {
    emit(Result.loading())
    try {
        emit(Result.success(fetchUser()))
    } catch(ioException: Exception) {
        emit(Result.error(ioException))
    }
}

Gradle yapılandırmanızda androidx.lifecycle:lifecycle-livedata-ktx:2.2.0veya daha üstünü kullanın .

Bununla ilgili bir makale de var.

Güncelleme : Ayrıca değiştirmek mümkün LiveData<YourData>de Dao interface. suspendAnahtar kelimeyi işleve eklemeniz gerekir :

@Query("SELECT * FROM the_table")
suspend fun getAll(): List<YourData>

ve ViewModelbu şekilde eşzamansız olarak almanız gerekir:

viewModelScope.launch(Dispatchers.IO) {
    allData = dao.getAll()
    // It's also possible to sync other data here
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.