欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Flow轉LiveData數據丟失原理詳解

 更新時間:2023年01月09日 08:39:27   作者:TechMerger  
這篇文章主要為大家介紹了Flow轉LiveData數據丟失原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

翻譯自:arkadiuszchmura.com/posts/be-ca…

最近我在負責一段代碼庫,需要在使用 Flow 的 Data 層和仍然依賴 LiveData 暴露 State 數據的 UI 層之間實現橋接。好在 androidx.lifecycle 框架已經提供了一個叫做 asLiveData() 的方法,可以讓你毫不費力地將 Flow 轉為 LiveData。

然而使用這種方式得到的 LiveData 需要牢記一點:在擁有一個及以上活躍的觀察者的條件下,它才會發(fā)射數據。假使上游的 flow 產生了更新,但對應的 LiveData 并非活躍的狀態(tài),那么它將無法獲得最新的數值。

讓我通過如下的實例,向你展示我們可能會遇到的這種潛在問題。

示例

我們有一個簡單的 Activity,它持有 AAC ViewModel 的實例:

 class MainActivity : AppCompatActivity() {  
     private val viewModel: MainViewModel by viewModels()  
     override fun onCreate(savedInstanceState: Bundle?) {  
         super.onCreate(savedInstanceState)  
         setContentView(R.layout.activity_main)    
     }  
 }

ViewModel 的實現是這樣的:

 class MainViewModel : ViewModel() {  
     private val repository = Repository()  
     val state: LiveData<Int> = repository.state.asLiveData()  
 }

它持有一個 Repository 實例,充當瑣碎的數據層。

同時 ViewModel 還通過前面提到的 asLiveData() 方法,將 Repository 持有的 StateFlow 轉為了 LiveData 并對外暴露了其 State 數據。

Repository 的實現如下:

 class Repository {  
     private val _state = MutableStateFlow(-1)  
     val state: StateFlow<Int> = _state  
     suspend fun update() {  
         _state.emit(Random.nextInt(until = 1000))  
     }  
 }

它擁有一個包裹著 Integer 數據(初始值為 -1)的 StateFlow 示例,同時對外提供了一個方法允許外界更新它的 State:從 0 到 1000 之間取得一個新的隨機數。

試想一下,假使希望 Activity 創(chuàng)建的時候就能執(zhí)行這個數據更新。我們可以這么實現:

  • MainViewModel 內創(chuàng)建一個 init() 來做這個操作
  • Activity 的onCreate() 里調用該方法
 // MainViewModel
 fun init() {
     // update() is suspending, so we launch a new coroutine here
     viewModelScope.launch {  
         repository.update()
     }  
 }
 ?
 // MainActivity
 override fun onCreate(savedInstanceState: Bundle?) {  
     super.onCreate(savedInstanceState)  
     setContentView(R.layout.activity_main)  
     viewModel.init()
 }

這樣的話,Activity 創(chuàng)建的時候一個新的協程將被啟動,最終會調用 Repository 的 update() ,生成一個隨機數并發(fā)射到它的 State。

此外,我們可能還需要在 ViewModel 中去發(fā)送包含了新生成數值的事件出去??梢栽?ViewModel 中添加一個sendAnalyticalEvent() ,這樣可以在執(zhí)行完 Repository 的 update() 之后立即調用它。

 // MainViewModel
 fun init() {  
     viewModelScope.launch {  
         repository.update()  
         sendAnalyticalEvent() // <-- NEW
     }  
 }  
 private fun sendAnalyticalEvent() {  
     // Typically, we would schedule a network request here  
     val liveDataValue = state.value  
     val flowValue = repository.state.value  
     Log.d("Current number in LiveData", "$liveDataValue")  
     Log.d("Current number in StateFlow", "$flowValue")  
 }

該方法內,我們可以做些典型的操作,比如向后端服務器發(fā)送網絡請求。這里,讓我們僅僅在 Logcat 里打印來自 LiveData and Flow 的數值即可。

上面的運行結果相當出乎意料。你可能會爭辯道:LiveData 沒有獲取到最新的數值,是因為沒有足夠的時間從上游的 flow 中收集數據,不然的話肯定能夠拿到正確的數值。

但這個 case 里,不僅僅是 LiveData 獲得到的是錯誤的數值,它獲得到的是 null。而且請別忘了,它的存放在 Repository 里的初值是 -1。這只能代表一個意思:這里的 LiveData 壓根沒有從 StateFlow 里收集任何數據。

原因是我們還沒有開始觀察這個 LiveData,它自然會被當作是非活躍的。而且根據 asLiveData() 方法的文檔可以知道,在這種情況下 LiveData 不會從上游的 flow 收集任何數據。

asLiveData:Creates a LiveData that has values collected from the origin Flow.

上游 flow 數據的收集發(fā)生在 LiveData 變成活躍的時候,即 LiveData.onActive。如果 flow 尚未完成,而 LiveData 變成了非激活狀態(tài),即 LiveData.onActive,那么 flow 的數據收集將在timeoutInMs 參數指定的時間后被取消。除非在超時之前,LiveData 變成活躍狀態(tài)。

一旦我們開始在 Activity 里觀察 LiveData 的數據(因此將促使 LiveData 變成活躍狀態(tài)),它就能夠擁有正確的、最新的數值了。

 // MainActivity
 override fun onCreate(savedInstanceState: Bundle?) {  
     super.onCreate(savedInstanceState)  
     setContentView(R.layout.activity_main)  
     viewModel.init()  
     viewModel.state.observe(this) { // <-- NEW  
         Log.d("Current number in MainActivity", "$it")  
     }  
 }

如下是 Logcat 里新的輸出。

上面的示例里,我們采用的是 StateFlow,但規(guī)則同樣適用于 SharedFlow。

而且,情況將更加糟糕,因為當 LiveData 處于非激活狀態(tài)的時候,任何發(fā)送給 SharedFlow 的事件都將永久丟失(默認情況下 SharedFlow 不會將任何數值重新發(fā)送給新的訂閱者)。

總結

請時刻記住采用 asLiveData() 方法轉換 Flow 得到的 LiveData 將會和預期的稍稍不同:它只會在注冊了活躍觀察者的情況下發(fā)射數據。

就我個人而言,這種行為無可厚非:因為我們都還沒有觀察它、自然不會在意 LiveData 的數值是啥、能不能獲取得到。但話說回來,確實存在一些場景,需要在你尚未開始觀察的時候,去訪問 ViewModelLiveData 的當前數值。

通過閱讀這篇文章,我希望你在遇到這種獲取不到正確數值的情況時,不要驚訝、心中有數。

以上就是Flow轉LiveData數據丟失原理詳解的詳細內容,更多關于Flow轉LiveData數據丟了的資料請關注腳本之家其它相關文章!

相關文章

  • Android入門之Activity間互相傳值詳解

    Android入門之Activity間互相傳值詳解

    我們在之前的Service篇章中看到了一種putExtras和getExtras來進行activity與service間的傳值。而恰恰這種傳值其實也是Android里的通用傳值法。它同樣可以適用在activity與activity間傳值,本文就來和大家詳細講講
    2022-12-12
  • SafeList?in?Flutter?and?Dart小技巧

    SafeList?in?Flutter?and?Dart小技巧

    這篇文章主要為大家介紹了SafeList?in?Flutter?and?Dart小技巧,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • Android 事件分發(fā)詳解及示例代碼

    Android 事件分發(fā)詳解及示例代碼

    本文主要介紹Android 事件分發(fā),這里整理詳細的資料及簡單的示例來講解Android事件分發(fā)的知識,有需要的小伙伴可以參考下
    2016-08-08
  • Android檢測url地址是否可達的兩種方法

    Android檢測url地址是否可達的兩種方法

    今天小編就為大家分享一篇Android檢測url地址是否可達的兩種方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • Android開發(fā)筆記 最好使用eclipse

    Android開發(fā)筆記 最好使用eclipse

    值得注意一點的是,雖然Myeclipse比eclipse功能更強大,但是在具體的安卓開發(fā)過程當中,最好還是選用eclipse,sdk跟eclipse的兼容性更好
    2012-11-11
  • 使用ViewPager實現左右循環(huán)滑動及滑動跳轉

    使用ViewPager實現左右循環(huán)滑動及滑動跳轉

    今天實現了左右滑動,至于在最后一頁滑動跳轉,這個也做了但是效果不是太好,也希望有實現的朋友能夠分享下
    2013-01-01
  • Android開發(fā)實現Launcher3應用列表修改透明背景的方法

    Android開發(fā)實現Launcher3應用列表修改透明背景的方法

    這篇文章主要介紹了Android開發(fā)實現Launcher3應用列表修改透明背景的方法,結合實例形式分析了Launcher3相關配置文件與功能函數修改設置操作技巧,需要的朋友可以參考下
    2017-11-11
  • Android通知欄微技巧一些需要注意的小細節(jié)

    Android通知欄微技巧一些需要注意的小細節(jié)

    這篇文章主要介紹了Android通知欄微技巧,那些你所沒關注過的小細節(jié),小編把此文分享到腳本之家平臺,需要的朋友可以參考下
    2018-04-04
  • Android實現圓形圖片小工具

    Android實現圓形圖片小工具

    這篇文章主要為大家詳細介紹了Android實現圓形圖片小工具,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • android讀取Assets圖片資源保存到SD卡實例

    android讀取Assets圖片資源保存到SD卡實例

    本文為大家詳細介紹下android讀取Assets圖片資源保存到SD卡的具體實現,感興趣的各位可以參考下哈,希望對大家有所幫助
    2013-07-07

最新評論