動態

詳情 返回 返回

移動互聯網高級開發正式課VIP-碼牛第二期 - 動態 詳情

download:移動互聯網高級開發正式課VIP-碼牛第二期

Jetpack架構演化(一):初步運用flow,附加經典案例
在jetpack體系中 livedata的角色純地道粹是個橋接器,DataSource中獲取到數據,然後由viewmodel停止邏輯處置,最後被livedata.postValue到view層,獨一的價值是綁定了lifecycle, 只在頁面活潑(start)的時分承受數據
官方的一篇引見能夠參考:從 LiveData 遷移到 Kotlin 數據流 - 掘金
關於初學者來説運用lieveData的益處是足夠簡單和相對平安
引入flow主要由於以下幾點:

具有更友好的API,學習本錢較低
跟Kotlin協程、LiveData分離更嚴密,Flow可以轉換成LiveData,在ViewModel中直接運用
分離協程的作用域,當協程被取消時,Flow也會被取消,防止內存走漏
flow庫從屬於kotlin, livedata屬於Android, 拜託Android平台的限制關於將來跨平台開展有利

【flow是個冷數據流】
所謂冷流,即下游無消費行為時,上游不會產生數據,只要下游開端消費,上游才開端產生數據。
而所謂熱流,即無論下游能否有消費行為,上游都會本人產生數據。
下邊經過一個經典場景細緻描繪下flow(單純的flow,而stateFlow會在後續章節中解説)的運用
案例:一個菜譜應用app中,我想在一個頁面展現一個列表(recyclerview) ,此列表的每個item是個子列表,子列表依次為
方案菜譜列表;
珍藏菜譜列表;
依據食材挑選的菜譜列表;
依據食材獲取用户偏好的菜譜列表;

四個子列表需求四個接口來獲取,組裝好後來刷新最後的列表
其中每個列表都有可能是空,是emptylist的話這行就不顯現了,由於四個接口數據量大小不同,所以不會同一時間返回,同時又要保證這四個子列表按請求的次第來展現。
思緒:
設計數據構造,最外層的data:
data class ContainerData(val title : String , val list: List)
複製代碼
其中Recipe實體是每個菜譜
data class Recipe(val id: String,

               val name: String,
               val cover: String,
               val type: Int,
               val ingredients: List? = mutableListOf(),
               val minutes: Int,
               val pantryItemCount : Int )

複製代碼
模仿四個懇求為:
val plannlist = Request.getPlannlist()
val favouritelist= Request.getFavouritelist()
... 以此類推
假如依照請求四個懇求返回次序不同,同時請求在列表中按次第顯現,假如完成?
計劃一:能夠等候四個懇求都返回後然後組裝數據,刷新列表
能夠應用協程的await辦法:
val dataList = MutableLiveData<List>()

viewModelScope.launch {
// planner
val plannerDefer = async { Request.getPlannlist() }
// favourite
val favouriteDefer = async { Request.getFavouritelist() }
val plannerData = plannerDefer.await()
val favouriteData = favouriteDefer.await()

....省略後兩個接口
val list = listof(
Container("planner" , plannerData),

Container("favourite" , favouriteData),

...
)
dataList.postValue(list)
}
複製代碼
await() 辦法是掛起協程,四個接口異步懇求(非次第),等最後一個數據懇求返回後才會執行下邊的步驟
然後組裝數據應用liveData發送,在view中渲染
viewModel.dataList.observe(viewLifecycleOwner) {

 mAdapter.submitList(it)

}
複製代碼
此種方式簡單,並且有效處理了按次第排列四個列表的需求,缺陷是體驗差,假設有一個接口極慢,其他幾個就會等候它,用户看着loading不斷髮愣麼。
計劃二:接口間不再相互等候,哪個接口先回來就渲染哪個,問題就是如何保證次第?
有的同窗會有計劃:先定製一個空數據list
val list = listOf(
Container("planner", emptylist()),
Container("favourite", emptylist()),
...
)
複製代碼
然後先用adapter去渲染list,哪個接口回來就去之前的列表查找交換,然後adapter刷新對應的數據,當然能夠,不過會產生一局部邏輯膠水代碼,查找遍歷的操作。
此時我們能夠藉助flow來完成了
1 結構一個planner數據流
val plannerFlow = flow {

    val plannList = Request.getPlanlist()

emit(ContainerData("Planner", plannList))

}.onStart {
    emit(ContainerData("", emptylist()))
}

複製代碼
留意是個val 變量, 不要寫成 fun plannerFlow() 辦法,不然每次調用開拓新棧的時分新建個flow,並且會不斷保管在內存中,直到協程取消
其中onStart 會在發送正式數據之前發送,作為預加載。
然後我們就能夠結構正式懇求了
viewModelScope.launch {

  combine(plannerFlow , favouriteFlow , xxxFlow ,xxxFlow) { planner , favourites , xxx , xxx  ->
            mutableListOf(planner , favourites , xxx,xxx)
  }.collect {
            datalist.postValue(it)
     }
 }

複製代碼
combine 的官方註釋為
Returns a Flow whose values are generated with transform function by combining the most recently emitted values by each flow.
複製代碼
combine操作符能夠銜接兩個不同的Flow , 一旦產生數據就會觸發組合後的flow的活動,同時它是有序的。

Add a new 評論

Some HTML is okay.