Kotlin Flow响应式编程,基础知识入门
Kotlin在推出多年之后已经变得非常普及了。相信现在至少有80%的Android项目已经在使用Kotlin开发,或者有部分功能使用Kotlin开发。
关于Kotlin方面的知识,我其实分享的文章并不算多,主要内容都是集中在《第一行代码 第3版》这本书当中。看完这本书,相信你一定可以很好地上手Kotlin这门语言。
其实由于《第一行代码 第3版》这本书只有Kotlin版本,销量受到了很大的影响,远不及第2版的销量。出版社数次跟我沟通过,希望我能再出一个面向Java语言的版本,因为有很多的读者,尤其是高校群体,还是想看Java语言的书,但是都被我拒绝了。
我之所以会拒绝,是因为Kotlin对于Android开发者来说已经非常重要了。如果你真的希望成为一名优秀的Android开发者(这个标准在几年后会降低为合格的Android开发者),那么Kotlin就必学不可。
因为现代化Android开发技术栈里面涉及到的方方面面的新知识,几乎已经全面Kotlin化。如果还守着Java不放,那就意味着像协程、Compose等未来主流的Android技术栈都将完全与你无关。
而现在随着Kotlin的普及率越来越高,我也终于打算去写一些基于Kotlin语言的进阶技术内容了。目前的计划是把Flow和Compose的相关内容都写一写,先从Flow开始写起。那么我们的Kotlin Flow系列就此正式展开了。
我打算通过3篇文章,从Flow的基础入门知识开始写起,逐渐教会大家Flow的常见用法,适用场景,以及容易被人忽视的坑点和注意事项。希望大家通过学习这个系列的文章之后,都能比较熟练地使用Flow。
另外需要注意的是,Flow基于Kotlin和协程这两项技术。而本篇文章并不会介绍这两项技术,所以如果你还没有入门Kotlin以及协程的话,建议还是先去阅读《第一行代码 第3版》进行基础知识部分的学习。
前言就说到这里,那么我们正式开始吧。
/ Flow和响应式编程 /
先说说响应式编程。
从大概四五年前开始,响应式编程逐渐进入到移动开发领域,并且变得越来越火热。比较有代表性的那应该就是在Android领域无人不知,无人不晓的RxJava框架。
其实我对于RxJava并不算很熟悉,当初在网上也学过各种教程和文章,但由于工作上一直没能用得上,所以我现在还能记得住的知识点已经不太多了。
但是RxJava留给我至今的印象就是上手困难。这个响应式编程的思维,它和传统意义上比较简单直观的程序顺序执行的思维就是不太一样。
那么既然这种编程思维上手如此困难,为什么我们还要去学习和使用它呢?
为了要证明响应式编程到底有多好,网上已经有数不清的教程和文章在费尽心思去解释。因此这里我也就不再另辟蹊径拍脑袋再去原创一个了,我直接就引用Google官方的讲解示例。官方讲解视频链接:https://youtu.be/fSB6_KE95bU
比如说有一头小牛住在山脚下,山上有一个湖,小牛每天需要跑很远的路拎着水桶去湖边打水。
dependencies {
...
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
implementation "androidx.activity:activity-ktx:1.6.0"
implementation "androidx.fragment:fragment-ktx:1.5.3"
}
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textSize="20sp"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Start"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_view" />
</androidx.constraintlayout.widget.ConstraintLayout>
class MainViewModel : ViewModel() {
val timeFlow = flow {
var time = 0
while (true) {
emit(time)
delay(1000)
time++
}
}
}
class MainActivity : AppCompatActivity() {
private val mainViewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView = findViewById<TextView>(R.id.text_view)
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
lifecycleScope.launch {
mainViewModel.timeFlow.collect { time ->
textView.text = time.toString()
}
}
}
}
}
lifecycleScope.launch {
mainViewModel.flow1.collect {
...
}
mainViewModel.flow2.collect {
...
}
}
lifecycleScope.launch {
launch {
mainViewModel.flow1.collect {
...
}
}
launch {
mainViewModel.flow2.collect {
...
}
}
}
class MainActivity : AppCompatActivity() {
private val mainViewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView = findViewById<TextView>(R.id.text_view)
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
lifecycleScope.launch {
mainViewModel.timeFlow.collect { time ->
textView.text = time.toString()
delay(3000)
}
}
}
}
}
class MainActivity : AppCompatActivity() {
private val mainViewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView = findViewById<TextView>(R.id.text_view)
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
lifecycleScope.launch {
mainViewModel.timeFlow.collectLatest { time ->
textView.text = time.toString()
delay(3000)
}
}
}
}
}
欢迎关注我的公众号
学习技术或投稿
长按上图,识别图中二维码即可关注