day19 Kotlin coroutine flow with liveData in MVVM

恩,标题不知道怎麽下成中文

在之前的范例里,示范了如何用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

而flow的优势就是

  1. 可以轻易的切换thread
  2. 减少样板code
  3. structure consurrency

flow with liveData
透过替换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


<<:  D20 - 「呐,你想要成为什麽颜色?」:将色彩传下去

>>:  [火锅吃到饱-12] 温野菜日本涮涮锅专门店 Taiwan On-Yasai @秀泰-台中站前店

dos指令 开启IIS 管理员

C:\Windows\System32\inetsrv InetMgr.exe ...

Day 10:一起了解 Angular 应用程序的启动流程(二)

前一篇我们提到了一部分的启动流程,今天我们会探讨剩下的启动流程资讯。 首先,我们要先知道 JavaS...

display : Inline、Block、Inline-Block

display:Inline、Block、Inline-Block 前言 display是用来设置每...

Web基础篇

先宣传一下我的新书,终於出来惹,感动到无法言语>"< 还请大家多多支持! We...

Day 0x15 UVa10056 What is the Probability ?

Virtual Judge ZeroJudge 题意 输入玩家数与成功机率,输出 I-th 玩家成...