恩,標題不知道怎麼下成中文
在之前的範例裡,示範了如何用coroutine做一次性的網路請求,並交結果post給liveData,讓ui可以觀察(one shot request)
今天,我會聊聊如何將flow用在相同的架構裡面,對observer的資料如何處理,用flow是想解決什麼問題,以及code範例,flow的內容會分成兩篇講,今天用flow和liveData合作,去更新ui
那以前做不到嗎?為什麼要引入flow呢?
其實以前也是能做到的,方法是透過liveData每一層,但和flow相比
liveData要改變內容比較不方便,而且必須是在main thread,最根本的原因就是liveData本來就不是為了當數據流而設計的
同時,這樣的code在clean architecture裡面,並不合適,因為liveData是只有android才有的
貼個圖,因為我也沒有用liveData寫過,所以我去問了別人
順便補個連結,如果有在維護舊專案的人,全用liveData的可以參考這篇LiveData beyond the ViewModel
而flow的優勢就是
透過替換repo和data source的live,實現更有彈性也更易讀的架構
看看code吧
如果不改變資料的話,其實沒差多少
//viewModel
val liveDataResult = repo.postLiveData
val flowResult = repo.postFlow.asLiveData()
添加初始值,覺得讀起來更好懂
val liveDataResult = liveData {
emit(0)
emitSource(repo.postLiveData)
}
val flowResult =
repo.postFlow
.onStart { emit(0) }
.asLiveData()
而最重要的,我們講過liveData對資料變更比較不友善,看看code吧
//咦,為甚麼不用liveData的map呢? 因為map跑在main thread
val liveDataResult =
repo.postLiveData.switchMap {
liveData {
emit( calculateSomething(it) )//繁重的計算需要切換thread, 可以用coroutine的liveData builder
}
}
val flowResult =
repo.postFlow
.map { calculateSomething(it) }
.asLiveData()
其實liveData也能處理,就是得寫更多樣版code,而flow寫起來更加直覺,對吧
先別看到這裡就著急說,ㄟ這flow最後還不是得轉成liveData,那我學個毛線?我原本在猶豫要不要講這篇flow with liveData,畢竟之後還會講怎麼完全不用到liveData
但在實際開發上java並沒有coroutine,有些專案是kotlin混java的,甚至是在維護舊專案,要加入新需求,要是只有全flow跟全liveData,引入新技術時會做很多不必要的重工(重寫沒問題的code,測試),所以我才決定留著這一篇
非常的簡單,model層我先寫的跟之前的範例一樣用retrofit,在實際開發上,對這種observer的資料,大多會用socket或推播,但也有long polling(聽說比較大多被socket取代),但這篇的簡單範例先用最笨的兩秒打一次
//connect interface
@GET("posts/{num}")
suspend fun getPostFlow(
@Path ("num") num: Int
): Post
//repo
//每兩秒fetch一個新資料
var count = 1
val postFlow: Flow<Post> = flow {
while (true){
val result = service.getPostFlow(count)
emit(result)
count++
delay(2000L)
}
}
//viewModel
val changeId = repo.postFlow.map {
it.id = -1
it
}.asLiveData()
//fragment
viewModel.changeId.observe(viewLifecycleOwner){
binding.apiResultText.text = it.toString()
}
因為太簡單了,實在懶得分開寫
LiveData:还没普及就让我去世?我去你的 Kotlin 协程
liveData with coroutine and flow-1
liveData with coroutine and flow-2
liveData with coroutine and flow-3