Kotlin Flow实际开发的几个场景问题

来源:13-9 案例:协程在 Android 中的应用

默小铭

2021-11-24

以下代码就是在ViewModel定义两个方法,写法一是直接将结果通过StateFlow传给View层处理,写法二和老师课程类似,直接把密封类传给View层,让View层判断密封类对应状态处理

写法一:

//把数据的处理也交给仓库层了,
    private val _stateFlowObs = MutableStateFlow<List<String>>(emptyList())

    val stateFlowObs: StateFlow<List<String>> = _stateFlowObs

    fun getDogImages3(isSuccess: Boolean) = viewModelScope.launch {

        //NetRequestRepository.getDogFire(isSuccess)
        NetRequestRepository.getDogImages(isSuccess)
            .onStart {
                //flow 调用数据之前回调,
                // 可用作 正在加载数据... Loading视图
            }.catch {
                //捕获上游出现的异常,这里指请求框架
            }
            .onCompletion {
                //请求完成
                //可用作 正在加载数据... Loading视图关闭
            }
            .collectLatest { result ->
                //在一段时间内发送多次数据,只会接受最新的一次发射过来的数据
                result.doFailure { throwable ->
                    _failure.value = throwable?.message ?: "failure"
                }
                result.doSuccess { value ->
                    //这个相当于 LiveData.setValue()
                    _stateFlowObs.value = value
                }
            }
    }

//------------StateFlow 仿LiveData 写法(直接把密封类发送出去,让宿主自己处理)---------------

写法二:

private val _uiState =
        MutableStateFlow<ResultWrapper2>(ResultWrapper2.Success<List<String>>(emptyList()))

    val uiState: StateFlow<ResultWrapper2> = _uiState

    fun getDogImages4(isSuccess: Boolean) = viewModelScope.launch {
        NetRequestRepository.getDogImages2(isSuccess)
            .onStart {
                //flow 调用数据之前回调,
                // 可用作 正在加载数据... Loading视图
            }.catch {
                //捕获上游出现的异常,这里指请求框架
            }
            .onCompletion {
                //请求完成
                //可用作 正在加载数据... Loading视图关闭
            }
            .collectLatest { result ->
                _uiState.value = ResultWrapper2.Success(result)
            }

    }

疑问场景一:

如果说一个页面只有一个网络请求,那么可以判断密封类状态,或者如果在onStart()/onCompletion()中对加一个状态控制LoadingDialog显示/隐藏,那么如果一个页面有多个请求的情况该怎么做呢??

目前自己想过的方案

  1. 协程实现 异步任务串行执行,然后在第一个请求实现 onStart() ,在最后一个请求实现 onCompletion(),来控制LoadingDialog的显示隐藏
  2. 协程实现 异步任务串行执行,调请求时自己先显示LoadingDialog,待执行完所有请求后

疑问场景二:

一个网络请求的的结果是另一个网络请求的参数,比方微信授权登录,登录成功后拿到userId,然后拿userid调微信接口,获取更详细的用户信息

目前自己想过的方案

  1. 老方案,ViewModel定义两个方法 funA()获取userID,然后View层,再将userID传给funB()获取用户详情
  2. Flow嵌套使用,自己瞎试,还没验证过的,如下伪代码
fun getDogImages4(isSuccess: Boolean) = viewModelScope.launch {
        //FlowA
        NetRequestRepository.getDogImages2(isSuccess)
            .collect { result ->
                _uiState.value = ResultWrapper2.Success(result)

                //FlowB
                NetRequestRepository.getDogFire(true).collect {
                    //do someThing
                }

            }

    }
写回答

2回答

bennyhuo

2021-11-25

课程设计的时候还没有 StateFlow,我目前还没有在项目里面用到(还是livedata),不过感觉上应该比较类似。

至于你说的多个异步的情况,能用挂起函数串行去写就不要用回调。

0
0

bennyhuo

2021-11-25

Flow实际上是协程对响应式思想的实现,如果你以前用过RxJava,可以简单地理解为支持了suspend 函数的RxJava。

0
0

学会Kotlin 突破开发语言瓶颈

如果有一门语言可以取代Java,那么它一定是Kotlin。

1760 学习 · 481 问题

查看课程