簡體   English   中英

如何知道 viewModel 的作業何時完成

[英]How to know when job from viewModel is done

我想弄清楚協同程序的工作是如何工作的。 基本上,我想從FirstFragment啟動這個協程,然后導航到SecondFragment並在完成這項工作時得到通知。 我在FirstFragment onViewCreated() ) 中調用getData() ) 並導航到SecondFragment 無論我在SecondFragment中編寫getData().isCompleted還是getData().invokeOnCompletion { }都沒有任何反應。 我不知道我是否遺漏了什么或沒有正確開始工作或其他什么。

private val _data = MutableStateFlow<GetResource<String>?>(null)
val data: StateFlow<GetResource<String>?> = _data

fun getData() = viewModelScope.launch {
    repository.getData().collect {
        _data.value = it
    }
}

來自數據庫的流程永遠不會完成,因為它應該無限期地監視數據庫的更改。 它僅在協程被取消時停止。 因此收集這樣一個 Flow 的 Job 永遠不會完成。 此外,如果您再次調用 repo 上的getData() ,您每次都會獲得一個新的 Flow 實例。

無論您在做什么,您都需要通過將其范圍限定到 Activity 來確保在兩個片段之間使用相同的 ViewModel 實例。 (例如by activityViewModels()使用。)這樣viewModelScope就不會在 Fragment 之間的轉換期間被取消。

如果您一次只需要回購中的一個項目,那么最簡單的事情可能是從回購中公開一個暫停 function 而不是 Flow。 然后把它變成一個Deferred。 也許通過將其設為Lazy ,您可以有選擇地決定何時開始檢索值。 如果您只想在第一個 Fragment 啟動時立即開始檢索值,請省略lazy

// In the shared view model:
val data: Deferred<GetResource<String>> by lazy { 
    viewModelScope.async {
      repository.getData() // suspend function returning GetResource<String>
    }
  }

fun startDataRetrieval() { data } // access the lazy property to start its coroutine

// In second fragment:
lifecycleScope.launch {
  val value = mySharedViewModel.data.await()
  // do something with value
}

但是,如果您因為將其用於其他目的而必須擁有 Flow:

如果您只想要 Flow 中的第一個可用值,請讓第二個 Fragment 監視您的data StateFlow 的第一個有效值。

lifecycleScope.launch {
  val value = mySharedViewModel.data.filterNotNull().first()
  // do something with first arrived value
}

您可以使用 SharedFlow,這樣您就不必將數據類型設置為可為空。 如果你這樣做,你可以省略上面的filterNotNull() 在您的 ViewModel 中,使用shareIn比必須使用支持屬性並手動收集源的代碼更容易做到這一點。

val data: SharedFlow<GetResource<String>> = repository.getData()
  .shareIn(viewModelScope, replay = 1, SharingStarted.Eagerly)

如果您需要在開始收集到 SharedFlow 之前等待,那么您可以將該屬性設為惰性。

同意@Tenfour04 的回答,我想多貢獻一點。 如果您真的想控制作業或結構化並發,我建議使用自定義方式處理協程,而不是將您的代碼與viewModelScope耦合。

您需要確保幾件事:
1- 發生取消或異常時會發生什么
2-您必須管理協程的生命周期(CoroutineScope)
3- 取消 scope,取決於用例,例如您現在面臨的問題
4- ViewModel 的 Scope 例如:它要么綁定到活動(共享 ViewModel),要么綁定到特定片段。

如果您沒有特別小心地處理其中任何一個,特別是前 3 個,您更有可能泄漏協程,您的應用程序肯定會出現不當行為。
每當您以自定義方式啟動任何協程時,您都必須確保生命周期是什么,何時結束,這非常重要,它可能會導致真正的問題
幸運的是,我有這個使用作業的 CustomViewModel 示例: 結構化並發示例代碼

暫無
暫無

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

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