概述
RxJava has been around for a few years now and has been one of the main building blocks for many Android projects to date. Kotlin’s Flow is taking a serious shot at contending for this spot, but can it replace RxJava or is it too immature still to fit our needs? Let’s dive straight in and have a look at the basics, getting from API calls to our UI only using Kotlin’s Flow with LiveData, ViewModel and the repository pattern! RxJava已经存在了好几年,并且迄今为止已经成为许多Android项目的主要构建块之一。 Kotlin的Flow在争夺这个位置方面正认真对待,但是它可以代替RxJava还是仍然不成熟以满足我们的需求? 让我们直接看一下基础知识,仅使用Kotlin的Flow和LiveData,ViewModel和存储库模式从API调用进入我们的UI! Kotlin Flow is an addition to Kotlin Coroutines. Coroutines save us from callback hell by giving us the possibility to run asynchronous code as if it was synchronous. Flow takes this a step further by adding streams to the mix. Why not use Coroutines channels you say? Channels are hot, meaning if we call a channel but don’t consume its data (yet), it’s lost. Flows are cold, so we receive the data once we start to collect it (like we did with subscribing to streams in RxJava). Kotlin Flow是Kotlin Coroutines的补充。 协程使我们有可能像运行同步代码一样运行异步代码,从而使我们免于回调地狱。 Flow通过向混合物中添加流,使这一步骤更进一步。 为什么不使用您所说的协程渠道? 通道很热,这意味着如果我们调用通道但不使用其数据(尚未),则该通道将丢失。 流程很冷,因此一旦开始收集数据,我们就会收到数据(就像我们在RxJava中订阅流一样)。 Let’s start things off by having a look at our architecture. We’ll stick with the MVVM pattern here, combined with the repository pattern for our data layer. Normally with RxJava, we’d use Observables (or variants of that: Singles, Completables, etc.) throughout our data layer, handle that in our ViewModel and use LiveData to push it to our UI. With Kotlin Flow, we’ll step away from the Observables and use 让我们从看看我们的架构开始。 我们将在这里坚持MVVM模式,并结合我们数据层的存储库模式。 通常,在RxJava中,我们会在整个数据层中使用Observables(或它的变体:Single,Completables等),在ViewModel中处理它,并使用LiveData将其推送到我们的UI。 使用Kotlin Flow,我们将远离Observables,将 Retrofit is our go-to library for consuming REST API’s and is a breeze to work with. If we’d like to use Flow in our data layer we don’t need any additional dependencies to get it running. Retrofit supports Retrofit是我们使用REST API的首选库,并且可以轻松使用。 如果我们想在数据层中使用Flow,则不需要任何其他依赖关系即可使其运行。 从 Network layer, done! ✅ 网络层,做完了! ✅ So, let’s say we’d like to return the response from our network call through our repository in a 因此,假设我们现在想通过 Alternatively, you have functions like 或者,也有功能类似于 Once we have our 一旦我们有了 And there you go, our repository now executes an API call and maps it to UI objects on the 随您去,我们的存储库现在执行一个API调用,并将其映射到 We have a couple of options in our ViewModel for handling our Flows. We’ll start off with a simple version that looks more like how we used to do things in RxJava. For usage of the 我们的ViewModel中有两个选项可以处理Flow。 我们将从一个简单的版本开始,该版本看起来更像我们以前在RxJava中执行操作的方式。 要使用 So, we have a repository that returns a 因此,我们有一个返回 Since we can only call the 由于我们只能从协程或暂停函数调用 Cool, we just pushed data from our API call all the way to our LiveData to observe in our UI! But how about when an error occurs or we want to start things off with different data? Flow got you covered! We can 太好了,我们只是将API调用中的数据一直推送到LiveData中,以便在用户界面中进行观察! 但是,何时发生错误,或者我们想从其他数据开始呢? 流程让您覆盖了! 当流程开始通过 Awesome! We’re now handling data and pushing multiple values to the UI! 太棒了! 现在,我们正在处理数据并将多个值推入UI! Instead of setting the value of our LiveData manually as we did in our previous example, we can also make use of 除了像前面的示例中那样手动设置LiveData的值之外,我们还可以使用 And that’s it, using Flow with LiveData builder! ???? Note that once the code-block within LiveData builder executed and completed successfully, it won’t be restarted at a later stage. It’ll only restart if the builder itself canceled the execution (due to inactive observers for example). 就是这样,使用Flow与LiveData构建器! ????请注意,LiveData构建器中的代码块一旦成功执行并完成,就不会在以后重新启动。 仅当构建器本身取消执行时才会重启(例如,由于非活动观察者)。 Tip: LiveData builder has a configurable timeout, meaning you can adjust the time it takes until the code-block within the builer cancels out when there are no active observers anymore. 提示:LiveData构建器具有可配置的超时,这意味着您可以调整在不再有活动的观察者的情况下直到buyler中的代码块消失为止所花费的时间。 And there you go! This is how to use Kotlin Flow in an Android Project in a nutshell. Implementing it was a total breeze! We’ve been putting it in one of our production apps here at PINCH and I really loved it. Having some experience with RxJava does help, but I definitely think the learning curve is less steep. Plus, it saves us a bunch of dependencies in our project. I’d definitely recommend using it, at least to experience it for once. 然后你去了! 简而言之,这就是在Android项目中使用Kotlin Flow的方法。 实施起来真是轻而易举! 我们一直将它放在 PINCH的 一个生产应用程序中 ,我真的很喜欢它。 拥有一些RxJava的经验确实有帮助,但是我绝对认为学习曲线并不那么陡峭。 另外,它为我们节省了项目中的大量依赖项。 我绝对建议您使用它,至少要一次体验一下。 Happy coding! ???? 编码愉快! ???? 翻译自: https://proandroiddev.com/kotlin-flow-on-android-quick-guide-76667e872166 重点 (Top highlight)
那是什么? ???? (What’s that? ????)
建筑 (Architecture)
suspend
functions combined with Flows. This means our architecture will look somewhat like this:suspend
功能与Flows结合使用。 这意味着我们的架构将看起来像这样: 翻新网络通话 (Network calls with Retrofit)
suspend
functions since version 2.6.0
, which is just what we need! No need to return Observables, Singles, Flowables, Completables or even Maybes, you just return your desired object or response and add suspend
to the function:2.6.0
版开始, 2.6.0
版支持suspend
功能,这正是我们所需要的! 无需返回Observables,Single,Flowables,Completables甚至Maybes,只需返回所需的对象或响应,然后将suspend
添加到函数中即可: @GET("foo")
suspend fun getFoo(): List<Foo>
资料库 (Repository)
Flow
now. We can start off by wrapping something in flow { ... }
. In there, we can do the work that needs to be done (do the API call for example) and use emit
to push a new value.Flow
的存储库返回来自网络调用的响应。 我们可以通过在flow { ... }
包装某些内容开始。 在这里,我们可以完成需要完成的工作(例如,执行API调用),并使用emit
推送新值。
flowOf()
or extension functions such as asFlow()
which also convert objects to a Flow and emit its content directly. Just have a look at what fits your needs ????flowOf()
或扩展函数如asFlow()
也对象转换为一个流,并直接发射其内容。 看看适合您的需求???? Flow
in place, we can do some mapping in our repository through the .map { ... }
operator and add threading by using .flowOn(...)
.Flow
,就可以通过.map { ... }
运算符在存储库中进行一些映射,并使用.flowOn(...)
添加线程。 class FlowRepository(private val api: FlowApiService) {
fun getFoo(): Flow<List<Foo>> {
return flow {
// exectute API call and map to UI object
val fooList = api.getFoo()
.map { fooFromApi ->
FooUI.fromResponse(fooFromApi)
}
// Emit the list to the stream
emit(fooList)
}.flowOn(Dispatchers.IO) // Use the IO thread for this Flow
}
fun getFooAlternative(): Flow<List<Foo>> {
return api.getFoo()
.map { fooFromApi -> FooUI.fromResponse(fooFromApi)}
.asFlow()
.flowOn(Dispatchers.IO)
}
}
IO
thread, all handled through Flow
!IO
线程上的UI对象,所有这些都通过Flow
处理! 视图模型 (ViewModel)
liveData
builder, check the part down below.liveData
构建器,请检查下面的部分。 Flow
, but how do we handle that data and push it to our UI? We start off with our usual suspects: both a mutable and immutable LiveData
object. What we’d like to do is push values to the mutable variable, so the first question is how to retrieve the data through our repository. Getting data of a Flow is simple: use the collect { ... }
function! Remember that mapped list we pushed in our repository by using emit
? That data will end up in collect
.Flow
的存储库,但是我们如何处理该数据并将其推送到我们的UI? 我们从通常的怀疑出发:一个可变且不变的LiveData
对象。 我们要做的是将值推送到可变变量,因此第一个问题是如何通过我们的存储库检索数据。 获取Flow的数据很简单:使用collect { ... }
函数! 还记得我们通过使用emit
推送到存储库中的映射列表吗? 这些数据最终将被collect
。 collect
from either a coroutine or suspending function, we’ll use the viewModelScope
to launch our Flow and collect the data:collect
,因此我们将使用viewModelScope
启动Flow并收集数据: private val _foo = MutableLiveData<List<FooUI>>()
val foo: LiveData<List<FooUI>> get() = _foo
fun loadFoo() {
viewModelScope.launch {
fooRepository.getFoo()
.collect { fooItems ->
_foo.value = fooItems
}
}
}
emit
a value when the flow starts collecting data through onStart { ... }
and if an error occurs we can catch it through catch { ... }
.onStart { ... }
收集数据时,我们可以emit
一个值,如果发生错误,我们可以通过catch { ... }
来捕获它。 private val _foo = MutableLiveData<List<FooUI>>()
val foo: LiveData<List<FooUI>> get() = _foo
fun loadFoo() {
viewModelScope.launch {
fooRepository.getFoo()
.onStart { /* _foo.value = loading state */ }
.catch { exception -> /* _foo.value = error state */ }
.collect { fooItems ->
_foo.value = fooItems
}
}
}
catch
will consume the exception, but you can also make use of onCompletion
to handle the exception and still continue downstream. onCompletion
will be triggered when the flow completes and returns an exception if an error occurred or null
if the stream completed successfully.catch
将消耗异常,但是您也可以使用onCompletion
来处理异常,并且仍然继续向下游。 流完成时将触发onCompletion
如果发生错误,则返回异常;如果流成功完成,则返回null
。 LiveData构建器 (LiveData builder)
liveData
builder. Look at it as a scope to your LiveData object: it’ll trigger when some UI starts observing the LiveData and cancels if there are no (more) observers before it completed. Using LiveData builder is easy! We have two options here: wrap the code we want to execute in liveData { ... }
and emit
a value or use the asLiveData()
extension function for a Flow (which basically does the same thing).liveData
构建器。 将其视为您的LiveData对象的作用域:当某些UI开始观察LiveData时,它将触发该事件;如果在完成之前没有(更多)观察者,则它将取消。 使用LiveData Builder很容易! 这里有两个选项:将要执行的代码包装在liveData { ... }
并emit
一个值,或者对asLiveData()
使用asLiveData()
扩展函数(基本上可以完成相同的操作)。 val foo: LiveData<List<FooUI>> = liveData {
fooRepository.getFoo()
.onStart { /* emit loading state */ }
.catch { exception -> /* emit error state */ }
.collect { fooItems ->
emit(fooItems)
}
}
val foo2: LiveData<List<FooUI>> = fooRepository.getFoo()
.onStart { /* emit loading state */ }
.catch { exception -> /* emit error state */ }
.asLiveData()
最后
以上就是暴躁未来为你收集整理的Android上的Kotlin Flow快速指南 那是什么? ???? (What’s that? ????) 建筑 (Architecture) 翻新网络通话 (Network calls with Retrofit) 资料库 (Repository) 视图模型 (ViewModel) LiveData构建器 (LiveData builder)的全部内容,希望文章能够帮你解决Android上的Kotlin Flow快速指南 那是什么? ???? (What’s that? ????) 建筑 (Architecture) 翻新网络通话 (Network calls with Retrofit) 资料库 (Repository) 视图模型 (ViewModel) LiveData构建器 (LiveData builder)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复