簡體   English   中英

在 ViewModel 中觀察 LiveData 最佳實踐

[英]Observing LiveData in ViewModel best practices

我正在尋找在ViewModel中觀察數據的最佳方式。

我正在使用 MVVM + 數據綁定。

存儲庫:

private val data = MutableLiveData<String>()

suspend fun getData(): LiveData<String> {
        return withContext(IO) {
            val response = apiRequest { api.getData() }
            data.postValue(response)
            data
        }
    }

它從服務器請求數據並返回實時數據。 ViewModel 必須觀察數據的變化。

視圖模型:

    suspend fun getData() {
        val data = repository.getData()
        MediatorLiveData<String>().apply {
            addSource(data) {
                gotData(it)
                removeSource(data)
            }
            observeForever { }
        }
    }

    private fun gotData(data: String) {
        //use data
    }

ViewModel 使用MediatorLiveData來觀察來自存儲庫的LiveData的變化。 我已將數據添加為源以觀察更改並在觸發后將其刪除,以防止在我多次獲取數據時多次觸發事件。 並且MediatorLiveData必須有一個虛假的觀察者,因此MediatorLiveData的 onChange 方法會觸發。

假設我只需要數據來隱藏/顯示視圖(甚至將數據填充到我的 recyclerview 適配器)。 然后我只需調用下面的代碼並使用這樣的 Observable 和 DataBinding:

val adapter: ObservableField<DataAdapter> = ObservableField()
val recyclerviewVisibility: ObservableField<Int> = ObservableField(View.GONE)
...
...
recyclerviewVisibility.set(View.VISIBLE)
adapter.set(DataAdapter(dataList))

所以我不需要將數據傳遞給FragmentActivity來使用viewLifecycleOwner 我也不能在ViewModel中使用observeForever ,因為在某些情況下它可能會多次觸發 onChange 方法。

有沒有更好的方法來獲取和觀察ViewModel中的數據?


解決方案:

我發現達到我的目標的最好方法是在不使用LiveData的情況下從存儲庫中獲取數據:

存儲庫

suspend fun getData() : String{
    return  apiRequest { api.getData() }
}

視圖模型

suspend fun getData(){
   val data = repository.getData()
    gotData(data)
}

fun gotData(data: String) {
    //use data
}

現在簡單多了。


獎金:

擴大:

fun <T : Any> ViewModel.request(request: suspend () -> (T), result: (T) -> (Unit) = {}) {
    viewModelScope.launch {
        result(request())
    }
}

用法:

request({request.getData()}) {
    //use data
}

如果我認為問題正確,我認為您可以在LiveData上使用map轉換。

也許最好更改存儲庫代碼,如下所示:

private val reload = MutableLiveData<Unit>()

val data: LiveData<String> =
    reload.switchMap {
        liveData(IO) {
            emit(apiRequest { api.getData() })
        }
    }

fun reload() {
    reload.postValue(Unit) 
}

然后,在使用 map 轉換的ViewModel中,您可以截取發射值:

val data: LiveData<String> = 
    repository.data.map {
        gotData(it)
        it
    }

fun reload() {
    repository.reload() 
}

使用此結構,您將能夠在每次需要時調用 ViewModel 的reload() ,從而從 api 獲取新數據並將其發送到 ViewModel 的data上。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM