Kotlin Flow常见场景下的使用实例

 更新时间:2022年08月31日 14:55:41   作者:newki  
这篇文章主要为大家介绍了Kotlin Flow常见场景下的使用实例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

Kotlin Flow在开发中的常用场景使用

大家了解了 Flow 的创建与接收流程,了解 SharedFlow 创建的几种方式,各个参数的用途,了解了SharedFlow的 "青春版" StateFlow 的创建与接收,已经他们与 LiveData 的异同。

注:这里青春版打上引号,只是调侃而已,并不是说 StateFlow 比 SharedFlow 更加轻量,而是StateFlow使用更加简单,更加的场景化而已,使用起来感觉比较青春版而已。

那么在真实的开发环境中我们是如何使用Flow的呢?这里从几点举例说明一下。

一、网络请求搭载Retrofit

之前在网上看到有人提问,为什么Retrofit不能返回 Flow 这样的对象。使用一个 FlowCallAdapterFactory 那我就可以直接使用Flow来传递了。

不是不行,有第三方的依赖实现了此功能,为什么官方不出,其实官方已经给出了建议

如果我想使用flow来传递数据,有哪些方式返回Flow的方式呢?这里有几种方案

1.1 LiveDataCallAdapterFactory

Retrofit 增加了 LiveDataCallAdapterFactory,我们可以使用LiveData来包裹对象

interface NewsApi {
    @POST("/wanandroid")
    fun fetchNewsLiveData(
        @FieldMap map:Map<String,String>
    ):LiveData<ApiResponse<NewsBean>>
}

使用的时候

fetchNewsLiveData().asFlow()

这样不就转成了Flow了吗?如果想转为StateFlow 或者SharedFlow,可以继续shareIn stateIn 之类的方法转换为热流。

1.2 suspend

使用挂起函数直接返回对象,然后使用flow函数创建出Flow对象,也是非常的简单,这也是官方推荐的方式。

interface NewsApi {
    @POST("/wanandroid")
   suspend  fun fetchNews(
        @FieldMap map:Map<String,String>
    ):ApiResponse<NewsBean>
}

使用的时候,直接就创建了一个flow对象

flow {
  emit(fetchNews())
}

如果想转为StateFlow 或者SharedFlow,可以继续shareIn stateIn 之类的方法转换为热流。

这种网络数据使用Flow的方式,好处是可以很方便的进行合并,合流,展平等操作,很方便的使用操作符转换成我们想要的数据。

二、协程与Flow的选择与差异

协程与Flow的选择,什么情况下我应该使用协程请求网络,什么情况下我才使用Flow 来操作UI。

其实我们对于实时性不高的数据,我们可以使用 Kotlin 协程处理,而对于实时性较高的数据,我们可以用 Flow 来处理。

例如动态详情顶部是详情数据固定的数据,而底部是列表和点赞评论的数量,这些是动态的数据,那么我们再顶部就可以用协程请求,在底部我们使用Flow处理数据再通知其改变。

    @POST("/wanandroid")
    suspend fun fetchNews(
        @FieldMap map: Map<String, String>
    ): BaseBean<NewsBean>
    suspend fun fetchNewsDetail(): OkResult<NewsBean> {
        return extRequestHttp {
            DemoRetrofit.apiService.fetchNews(
                mapOf("id" to "12232", "key" to "2")
            )
        }
    }
    lifecycleScope.launch {
        val detail = mViewModel.mRepository.fetchNewsDetail()
        detail.checkSuccess {
            updateUI(it)
        }
    }
    private fun updateUI(newsBean: NewsBean?) {
       // XXX
    }

而下面的列表与动态点赞分享数据,我们可以使用 Flow 来操作,当点赞或转发数发生变化时,updateUI() 会被执行,UI根据最新的数据更新。

    private val _stateFlow = MutableStateFlow("")
    val stateFlow: StateFlow<String> = _searchFlow
    fun changeState() {
        viewModelScope.launch {
            val detail = mRepository.changeState()
            detail.checkSuccess {
                //进一系列的数据合流
                //进行一系列的排序、转换之后设置给Flow
                _stateFlow.value = it ?: ""
            }
        }
    }

操作UI的伪代码如下:

    private fun changeData() {
        mViewModel.changeState()
    }
    private fun updateUI() {
       //更新一些UI
    }
    override fun startObserve() {
        lifecycleScope.launchWhenCreated {
            mViewModel.stateFlow.collect {
                updateUI()
            }
        }
    }

是不是静态的页面不能用 Flow ,能不能用 LiveData ? 当然可以用了,上面的只是推荐使用,其他的方式当然都可以例如:

    fun getNewsDetail(): LiveData<NewsBean?> {
        return liveData {
            val detail = mRepository.fetchNewsDetail()
            if (detail is OkResult.Success) {
                emit(detail.data)
            } else {
                emit(null)
            }
        }
    }

使用的时候:

    fun getData(){
        mViewModel.getNewsDetail().observe(this) {
            updateUI()
        }
    }
    private fun updateUI() {
        //更新一些UI
    }

三、StateFlow与SharedFlow的选择

什么时候使用StateFlow ,什么时候使用 SharedFlow ,在之前 SharedFlow 的文章中,我们对比过 StateFlow,SharedFlow,LiveData 的区别。

关于 SharedFlow、StateFlow、LiveData的对比,个人的结论是:根据不同的场景 LiveData StateFlow SharedFlow 都有自己特定的使用场景,谁也无法真的完全平替谁。谁也不是谁的超集,都是各有利弊,按需选择即可。这里不过多赘述。

那其实从另一角度,我们区别不同的场景为状态和事件,看此场景是状态驱动还是事件驱动的。

比如我现在点击了按钮,需要弹窗了,然后使用StateFlow来记录状态,然后收集到这个事件弹出弹框了,然后我们关闭弹窗去浏览此页面的其他信息了了,但是当我们旋转手机屏幕之后,我们会发现弹窗又出来了。这就不合理了。

有同学说,这是StateFlow的问题,此情况我们需要使用LiveData,那LiveData就没有问题了吗?

我们测试一下:

@HiltViewModel
class Demo4ViewModel @Inject constructor(
    val mRepository: Demo5Repository,
    val savedState: SavedStateHandle
) : BaseViewModel() {
    val channel = Channel<String>(Channel.CONFLATED)
    private val _searchLD = MutableLiveData<String>()
    val searchLD: LiveData<String> = _searchLD
    private val _searchFlow = MutableStateFlow("")
    val searchFlow: StateFlow<String> = _searchFlow
    private val _sharedFlow = MutableSharedFlow<String>(replay = 1, onBufferOverflow = BufferOverflow.SUSPEND)
    val sharedFlow: SharedFlow<String> = _sharedFlow
    fun changeSearch(keyword: String) {
        _sharedFlow.tryEmit(keyword)
        _searchFlow.value = keyword
        _searchLD.value = keyword
        channel.trySend(keyword)
    }
}

我们测试 LiveData Channel StateFlow SharedFlow(replay=1)

点击按钮发送事件

旋转屏幕查看Log-3个数据

除了Channel,原来你们都会再次触发,别急我们修改SharedFlow(replay =0)

旋转屏幕查看Log-2个数据

SharedFlow就不会再触发了。

到这里,StateFlow 与 SharedFlow 的使用场景就应该很清晰了,状态(State)用 StateFlow ;事件(Event)用 SharedFlow

关于SateFlow SharedFlow LiveData 的对比可以看这里。

总结

Flow 的使用总的来说还是很广泛,如果你的项目是Kotlin语言开发的,强烈建议使用Flow。

关于LiveData 替换为Flow的问题,这几篇文章也给出了答案,看不同的场景,SateFlow SharedFlow LiveData 各有优缺点,无法真的说谁能真的完全平替谁。

以上就是Kotlin Flow常见场景下的使用实例的详细内容,更多关于Kotlin Flow使用场景的资料请关注脚本之家其它相关文章!

相关文章

  • Kotlin实现半圆形进度条的方法示例

    Kotlin实现半圆形进度条的方法示例

    这篇文章主要给大家介绍了关于Kotlin实现半圆形进度条的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧。
    2018-03-03
  • Android文件下载进度条的实现代码

    Android文件下载进度条的实现代码

    我们今天开始学习的是下载进度的实现。今天的这段代码是网上找的,自己做了些小改,通过模拟器测试。文件下载进度条控制(就是为了高清壁纸加个进度条),自己研究了好久,但是进度条只能显示缓存写入文件的进度,不能显示下载进度。找了好久,终于找到一段用的代码,所以记录下来,大家分享
    2013-01-01
  • Kotlin Fragment的具体使用详解

    Kotlin Fragment的具体使用详解

    Fragment是Android3.0后引入的一个新的API,他出现的初衷是为了适应大屏幕的平板电脑, 当然现在他仍然是平板APP UI设计的宠儿,而且我们普通手机开发也会加入这个Fragment, 我们可以把他看成一个小型的Activity,又称Activity片段
    2022-10-10
  • 解析android 流量监测的实现原理

    解析android 流量监测的实现原理

    本篇文章是对android中流量监测的实现原理进行了详细的分析介绍,需要的朋友参考下
    2013-06-06
  • android控件Banner实现简单轮播图效果

    android控件Banner实现简单轮播图效果

    这篇文章主要为大家详细介绍了android控件Banner实现简单轮播图效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • 哔哩哔哩Android项目编译优化

    哔哩哔哩Android项目编译优化

    这篇文章主要为大家介绍了哔哩哔哩Android项目编译优化详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Android 控件自动贴边实现实例详解

    Android 控件自动贴边实现实例详解

    这篇文章主要为大家介绍了Android 控件自动贴边实现实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • Android仿新浪微博、QQ空间等帖子显示(2)

    Android仿新浪微博、QQ空间等帖子显示(2)

    这篇文章主要为大家详细介绍了Android仿新浪微博、QQ空间等帖子显示,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-09-09
  • Android游戏开发学习①弹跳小球实现方法

    Android游戏开发学习①弹跳小球实现方法

    这篇文章主要介绍了Android游戏开发学习①弹跳小球实现方法,涉及Android通过物理引擎BallThread类模拟小球运动的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-10-10
  • Android实现自定义轮播图片控件详解

    Android实现自定义轮播图片控件详解

    这篇文章给大家主要介绍了Android实现自定义轮播图片控件的详细过程,文中通过实例代码介绍的很详细,相信会对大家的理解和学习很有帮助,感兴趣的朋友们下面来一起看看吧。
    2016-10-10

最新评论