簡體   English   中英

如何使用 kotlin 協程獲取數據並初始化 viewmodel 中的字段,而沒有 null 字段的延遲

[英]How can I get data and initialize a field in viewmodel using kotlin coroutines and without a latenite of null field

我有一個常見的獲取數據的情況。 我使用 Kotlin 協程。

1個變體:

class SomeViewModel(
    private val gettingData: GetDataUseCase
) : ViewModel() {

    lateinit var data: List<String>

    init {
        viewModelScope.launch {
            data = gettingData.get()
        }
    }
}

2 變體:

class SomeViewModel(
    private val gettingData: GetDataUseCase
) : ViewModel() {

    val data = MutableStateFlow<List<String>?>(null)

    init {
        viewModelScope.launch {
            data.emit(gettingData.get())
        }
    }
}

如何使用 viewModelScope 但沒有 lateinit 或 nullble 字段來初始化數據字段而不是延遲,而是立即 沒有 LiveData,我的項目使用 Coroutine Flow

我無法返回 viewModelScope 作業 in.run{} 或惰性 {} 的結果。 我無法返回一個有趣的結果:

val data: List<String> = getData()

fun getData(): List<String> {
    viewModelScope.launch {
        data = gettingData.get()
    }
    return ???
}

我也不能讓 suspend 有趣 getData() 因為我不能在初始化中創建 coroutineScope'

您必須將 SharedFlow 與 replay 1 一起使用(存儲最后的值並為新訂閱者重播)來實現它。

我的樣本:

interface DataSource {
    suspend fun getData(): Int
}

class DataViewModel(dataSource: DataSource): ViewModel() {
    val dataField =
        flow<Int> {
            dataSource.getData()
        }.shareIn(viewModelScope, SharingStarted.WhileSubscribed(1000), 1)
}

你描述的是不可能的。 據推測, gettingData.get()被定義為暫停 function,這意味着無法立即檢索結果。 由於檢索需要一段時間,因此您不能立即獲得價值。

這就是應用程序和網站在其 UI 中具有加載指示器的原因。

如果您使用的是 Flows,則可以使用具有可空類型的 Flow(如上面的選項 2),並且在您的 Activity/Fragment 中,在收集器中,您可以顯示加載指示器或您的數據,具體取決於它是null。

您的代碼 2 可以使用flow builder 和stateIn簡化,默認值為 null:

class SomeViewModel(
    private val gettingData: GetDataUseCase
) : ViewModel() {

    val data = flow<List<String>?> { gettingData.get() }
        .stateIn(viewModelScope, SharingStarted.Eagerly, null)

}

在您的活動或片段中:

viewLifecycleOwner.lifecycleScope.launch {
    viewModel.data
        .flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.STARTED)
        .collect { list ->
            if(list == null) {
                // Show loading indicator in UI
            } else {
                // Show the data
            }
         }
}

如果您的數據加載速度非常快,您可以將默認值emptyList()而不是使類型可為空。 那么當列表為空時,你的收集器就不能做任何事情。 如果數據加載速度足夠快,以至於用戶不會因為屏幕長時間空白而懷疑是否有問題,則此方法有效。

暫無
暫無

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

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