当前位置: 首页 > 科技观察

KotlinFlow响应式编程,基础知识入门

时间:2023-03-14 19:33:45 科技观察

Kotlin自推出以来多年来非常受欢迎。相信至少有80%的Android项目是使用Kotlin开发的,或者部分功能是使用Kotlin开发的。关于Kotlin的知识,其实我分享的文章不多,主要内容都集中在本书《第一行代码 第3版》中。看完本书,相信你一定能够很好的上手Kotlin语言。事实上,由于《第一行代码 第3版》这本书只有Kotlin版本,所以销量受到了很大的影响,远不及第二版的销量。出版社多次与我沟通,希望我能再出一个Java语言的版本,因为很多读者,尤其是高校的读者,还想看Java语言的书,都被我拒绝了.我之所以会说不,是因为Kotlin对于Android开发者来说已经非常重要了。如果你真的想成为一名优秀的Android开发者(这个标准将在几年内沦为一名合格的Android开发者),那么Kotlin是必须学习的。因为现代Android开发技术栈涉及到的方方面面的新知识几乎都已经完全Kotlin化了。如果你还死守着Java,意味着协程、Compose等未来Android主流技术栈都与你无缘。而现在随着Kotlin越来越受欢迎,我终于打算写一些基于Kotlin语言的进阶技术内容。目前的计划是同时写Flow和Compose,从Flow开始。那么我们的KotlinFlow系列就正式开始了。我打算通过3篇文章从Flow的基础入门知识开始,逐步教大家Flow的常用用法、适用场景以及容易被忽视的陷阱和注意事项。希望大家在学习完本系列文章后,能够更加熟练的使用Flow。另外需要注意的是,Flow基于两种技术,Kotlin和协程。本文不会介绍这两种技术,所以如果你还没有接触过Kotlin和协程,建议先阅读《第一行代码 第3版》了解基础知识。前言就这些了,让我们开始吧。流程与响应式编程先说响应式编程。从大约四五年前开始,响应式编程逐渐进入移动开发领域,并且越来越流行。比较有代表性的应该是Android领域人尽皆知、人尽皆知的RxJava框架了。其实我对RxJava不是很熟悉。也学习了网上的各种教程和文章,但是因为一直没能在工作中使用,所以还是没有记住太多的知识点。但是RxJava给我的印象就是入门难。这种响应式编程的思维不同于传统意义上相对简单直观的顺序执行程序的思维。那么既然这种编程思维如此难以入门,我们为什么要学习和使用它呢?为了证明响应式编程有多好,网上有无数的教程和文章竭尽全力地对其进行讲解。所以这里我不会再另辟蹊径敲脑打出原创了。我直接引用谷歌官方的解释例子。官方解说视频链接:https://youtu.be/fSB6_KE95bU比如山脚下住着一头小牛,山上有个湖。小牛每天需要跑很远的路去提着水桶从湖里打水。每天跑很远的路也没关系。关键是湖水时不时会干涸。有时小牛到了湖边,发现湖水已经干涸,这一趟就彻底白费了。时间长了,明眼人都能发现,这种挑水的方式实在是太蠢了。不如多花点时间建设基础设施,从湖边架一条水管到山脚下,让小牛再也不用跑很远的路去取水,每次打开水龙头就可以了他想喝水。.而判断湖水是否干涸也可以通过打开水龙头看是否有水来判断。并且在架设了一条管道之后,以后可以很方便的连接其他的管道。对于最终的水端来说,这个过程甚至可以是无感的,因为他只需要负责开关水龙头即可。在上面的例子中,提着水桶去湖边打水,可以类比我们平时的编程方式,需要什么的时候调用相应的函数。而通过架设水管在水龙头处排水和接水,堪比当下最流行的响应式编程。哇,看到这么形象的反差,这么巨大的反差,是不是觉得响应式编程这个概念牛逼,瞬间觉得自己以前的编程方式好low?其实我第一次看到这个类比的时候,也觉得这么强大的编程方法并不是很久以前就发明出来的。但是后来想了想,发现Google给出的例子其实经不起推敲。在如今的生活中,当然没有人愿意做提水桶挑水这种又苦又累的工作。转动水龙头是多么容易。但是在编程的世界里,我们平时调用一个函数并不是这么苦和累的词。相反,调用一个函数就像调用它来获取它的返回值一样简单。但是看似简单的水龙头,想要在程序中实现类似的功能(所谓的响应式编程),其实并不简单,这个水龙头的开关可不是那么容易控制的。所以,很多程序员在尝试过响应式编程之后,会觉得这没什么,再好的简单代码也得写这么复杂。没错,我也觉得响应式编程的思想对初学者来说不够友好,它可以把原本简单的代码复杂化,但确实可以解决一些不好解决的问题。就拿刚才打水的例子来说,调用一个函数打水很简单,但是如果打水的过程很耗时怎么办?在主线程中调用可能会导致程序卡死。所以这个时候就需要考虑开启子线程去打水,然后处理线程回调结果等一些事情。但是对于响应式编程,您需要做的就是打开水龙头。总之,我个人的感觉是,随着项目越来越复杂,你会越来越能感受到响应式编程的优势。而如果项目比较简单,很多时候使用响应式编程就是给自己找麻烦。好了,以上就是我对响应式编程的一些分析。所以在Android领域,之前最有影响力的响应式编程框架就是RxJava了。但是你也发现了,它是RxJava(虽然它也可以在Kotlin上使用)。Kotlin怎么受得了这个?因此,Kotlin团队开发了一套专门用于Kotlin的响应式编程框架,这就是我们系列的主角:Flow。Flow的基本使用在这篇文章中,我将通过一个最简单的例子来让你快速入门Flow的基本使用。因为太简单了,甚至在一些细节上是错误的。不过没关系,我会在后面的文章中详细介绍。目前,我们的目标是能跑。在AndroidStudio中新建一个FlowTest项目,让我们开始吧。那么什么是例子呢?很简单,就是在Android中实现一个定时器的效果,每一秒更新一次时间。但是必须使用Flow技术来实现。第一步是添加依赖库。如果想在Android项目中使用Flow,需要在项目中添加如下依赖库:dependencies{...implementation"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1"implementation"org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1"实现'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'实现"androidx.activity:activity-ktx:1.6.0"实现"androidx.fragment:fragment-ktx:1.5.3"}前两项是协程库,因为Flow是在Kotlin协程的基础上构建的,所以协程依赖必不可少。第三项用于提供协程的作用域,也是必不可少的。最后两项是ktx的扩展库。这些都不是必须的,但是可以帮助我们简化很多代码的编写,所以也建议加上。接下来,开始定义布局。布局文件activity_main.xml中的内容也很简单。一个Button用于开始计时,一个TextView用于显示时间:写完这些,我们基本上就做好了准备工作,接下来我们就用Flow技术来实现定时器功能回想刚才的类比,响应式编程就像使用水龙头接水。然后是整个过程中最重要的三个部分:水源、水管和水龙头。其中水源也是我们的数据源,这部分需要我们自己处理。水龙头是最终的接收端,可能会显示给用户,这部分也需要我们自己处理。水管是实现响应式编程的基础设施部分,它是由Flow封装的提供给我们的,不需要我们自己去实现。所以很明显,我们需要写的是水源和水龙头。从水源开始,定义一个MainViewModel类,并继承ViewModel,代码如下所示:classMainViewModel:ViewModel(){valtimeFlow=flow{vartime=0while(true){emit(time)delay(1000)time++}}}这里,使用流构造函数构造了一个timeFlow对象。在流构造函数的函数体内部,我们写了一个while循环,每次循环都会给time变量加1,每次循环都会调用delay函数延迟1秒执行。这里的延迟函数是协程中的挂起函数,只能在协程作用域或其他挂起函数中调用。因此可以看出,流构造函数也会将函数挂起的上下文提供给函数体内部。剩下的emit函数可以理解为一个数据发送器,它会将传入的参数发送给水管。总共只有几行代码,是不是很简单?这样我们就完成了水的部分。可能有朋友会说,这个timeFlow变量定义为全局变量,一开始就会执行。难道我们还没打算开始接水,这里的水源源源不断地送水?不是在这种情况下。因为使用流构造函数构造的Flow属于CodeFlow,也叫冷流。所谓冷流,就是Flow在没有任何接收端的情况下不会工作。只有当有接收端(水龙头打开)时,Flow函数体中的代码才会自动开始执行。好了,接下来我们开始实现tap部分,代码如下:setContentView(R.layout.activity_main)valtextView=findViewById(R.id.text_view)valbutton=findViewById