带有协程和 SavedStateHandle 的 liveData

liveData with Coroutines and SavedStateHandle

这个 answer 向我们展示了如何在存储库中使用 liveData 到 return 一个 LiveDataViewModel 其中 View会观察的。
现在,如果我们想使用 SavedStateHandle 怎么办?我们如何将以下代码转换为使用 liveData{} from LiveData-Ktx?

视图模型:

private val _itemLiveData = stateHandle.getLiveData<MyItem>(KEY, MyItem())
val itemLiveData: LiveData<MyItem> = _itemLiveData

suspend fun nextPage() {
    viewModelScope.launch {
        val item = repoCall...
        stateHandle.set(KEY, item)
    }
}

Activity:

viewModel.itemLiveData.observe(this, Observer {
    lifecycleScope.launch {/*...update ui...*/}
})

我们会从使用 liveData{... emit()} 中受益吗?

我可以看到使用 SavedStateHandle 的 3 个优点:
1 - 恢复您的 viewModel 状态
2 - 当我们使用 stateHandle.set()
时它会为我们调用 .value() 3 - stateHandle.getLiveData 帮助我们初始化值(这对 Data Binding 也有帮助,例如)

我想你可以这样做

class SomeViewModel(
    private val savedStateHandle: SavedStateHandle
    repository:ItemsRepository) : ViewModel() {

    companion object {
        private const val PAGE_KEY = "page_key"
    }

    private val _page = MutableLiveData<PageId>(savedStateHandle.get(PAGE_KEY))

    private val _itemLiveData = Transformations.switchMap(_page) { pageId -> repository.getNextPage(pageId) }
    val itemLiveData: LiveData<MyItem> = _itemLiveData

    suspend fun nextPage(pageId: PageId) {
        _page.postValue(pageId)
    }

    override fun onCleared() {
        super.onCleared()
        savedStateHandle.set(PAGE_KEY, _page.value)
    }
}


class ItemsRespository {

    fun getNextPage(pageId:PageId) = liveData() {
        ....
        emit(someData)
    }
}

如果对您有帮助,请告诉我。 P.S。 PageId 可以是当前页面的编号或其他任何页面标识符

实际上,对于 savedStateHandleget/set 方法对我来说是一个错误。唯一真正可靠的是 getLiveData,您可以使用 Transformations.switchMap.

将其合并到其他 LiveData 中

如果您将 getLiveDataandroid.os.Bundle 支持的类型一起使用,那么您可以通过它立即获得状态持久性。如果你不这样做,那么你只会崩溃。 getLiveData 已经 returns 一个 MutableLiveData,这就是为什么手动处理 get/set 不是一个好主意,您可以在 [=17= 上调用 .value = ] 来自 SavedStateHandle 如果需要的话。