我是靠谱客的博主 暴躁未来,最近开发中收集的这篇文章主要介绍Android上的Kotlin Flow快速指南 那是什么? ???? (What’s that? ????) 建筑 (Architecture) 翻新网络通话 (Network calls with Retrofit) 资料库 (Repository) 视图模型 (ViewModel) LiveData构建器 (LiveData builder),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

重点 (Top highlight)

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!

那是什么? ???? (What’s that? ????)

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中订阅流一样)。

建筑 (Architecture)

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 suspend functions combined with Flows. This means our architecture will look somewhat like this:

让我们从看看我们的架构开始。 我们将在这里坚持MVVM模式,并结合我们数据层的存储库模式。 通常,在RxJava中,我们会在整个数据层中使用Observables(或它的变体:Single,Completables等),在ViewModel中处理它,并使用LiveData将其推送到我们的UI。 使用Kotlin Flow,我们将远离Observables,将suspend功能与Flows结合使用。 这意味着我们的架构将看起来像这样:

Image for post

翻新网络通话 (Network calls with Retrofit)

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 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:

Retrofit是我们使用REST API的首选库,并且可以轻松使用。 如果我们想在数据层中使用Flow,则不需要任何其他依赖关系即可使其运行。 从2.6.0版开始, 2.6.0版支持suspend功能,这正是我们所需要的! 无需返回Observables,Single,Flowables,Completables甚至Maybes,只需返回所需的对象或响应,然后将suspend添加到函数中即可:

@GET("foo")
suspend fun getFoo(): List<Foo>

Network layer, done! ✅

网络层,做完了! ✅

资料库 (Repository)

So, let’s say we’d like to return the response from our network call through our repository in a 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推送新值。

Alternatively, you have functions like 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()也对象转换为一个流,并直接发射其内容。 看看适合您的需求????

Once we have our 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)
  }
}

And there you go, our repository now executes an API call and maps it to UI objects on the IO thread, all handled through Flow!

随您去,我们的存储库现在执行一个API调用,并将其映射到IO线程上的UI对象,所有这些都通过Flow处理!

视图模型 (ViewModel)

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 liveData builder, check the part down below.

我们的ViewModel中有两个选项可以处理Flow。 我们将从一个简单的版本开始,该版本看起来更像我们以前在RxJava中执行操作的方式。 要使用 liveData 构建器,请检查下面的部分。

So, we have a repository that returns a 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

Since we can only call the 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
      }
  }
}

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 emit a value when the flow starts collecting data through onStart { ... } and if an error occurs we can catch it through catch { ... }.

太好了,我们只是将API调用中的数据一直推送到LiveData中,以便在用户界面中进行观察! 但是,何时发生错误,或者我们想从其他数据开始呢? 流程让您覆盖了! 当流程开始通过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
      }
  }
}

Awesome! We’re now handling data and pushing multiple values to the UI!

太棒了! 现在,我们正在处理数据并将多个值推入UI!

catch will consume the exception, but you can also make use of onCompletionto 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)

Instead of setting the value of our LiveData manually as we did in our previous example, we can also make use of 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构建器。 将其视为您的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()

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

最后

以上就是暴躁未来为你收集整理的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)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部