使用RxJava和RxKotlin进行Kotlin反应式编程

自从成为Android开发受官方支持的语言以来,Kotlin在Android开发人员中Swift普及,Google称使用Kotlin创建的应用程序增长了6倍

如果您以前使用过RxJava或RxAndroid,并且想切换到Kotlin,或者想开始使用Kotlin进行反应式编程,那么本教程适合您。 我们将介绍在Kotlin中创建RxJava 2.0 ObserversObservables和数据流的要点,然后研究如何通过将RxJava与Kotlin扩展功能相结合来削减项目中的大量样板代码。

将RxJava与Kotlin结合使用可以帮助您以更少的代码创建具有高度响应性的应用程序,但是没有哪种编程语言是完美的,因此,我还将分享许多开发人员在刚开始将Kotlin与RxJava 2.0一起使用时遇到的SAM转换问题的解决方法。

总结一下,我们将创建一个应用程序,演示如何使用RxJava解决现实生活中的Android项目中遇到的一些问题。

如果这是您对RxJava的初次体验,那么在此过程中,我还将提供理解RxJava核心概念所需的所有背景信息。 即使您以前从未尝试过RxJava,到本文结尾,您也将对如何在项目中使用此库有深入的了解, 并且您将使用RxJava,RxKotlin,RxAndroid创建一些可运行的应用程序和RxBinding。

无论如何,什么是RxJava?

RxJava是ReactiveX库的开源实现,可帮助您以反应式编程风格创建应用程序。 尽管RxJava旨在处理同步和异步数据流,但它并不限于“传统”数据类型。 RxJava对“数据”的定义非常广泛,包括诸如缓存,变量,属性,甚至是用户输入事件(如单击和滑动)之类的东西。 仅仅因为您的应用程序不处理大量数据或执行复杂的数据转换,并不意味着它不能从RxJava中受益!

那么RxJava如何工作?

RxJava扩展了基于Observers和Observables概念的Observer软件设计模式。 要创建基本的RxJava数据管道,您需要:

  • 创建一个可观察的。
  • 给Observable发出一些数据。
  • 创建一个观察者。
  • 将观察者订阅到可观察者。

一旦可观察对象至少具有一个观察者,它将开始发出数据。 每次Observable发出一条数据时,它将通过调用onNext()方法通知其分配的Observer,然后Observer通常将响应此数据发出执行某些操作。 一旦Observable完成发送数据,它将通过调用onComplete()通知Observer。 然后,Observable将终止,并且数据流将结束。

如果发生异常,则将调用onError() ,并且Observable将立即终止,而不会发出更多数据或调用onComplete()

但是RxJava 不仅仅是将数据从Observable传递给Observer! RxJava有大量的运算符集合,可用于过滤,合并和转换这些数据。 例如,假设您的应用程序具有检测“ onClick事件的“ 立即付款”按钮,并且您担心不耐烦的用户可能多次点击该按钮,从而导致您的应用程序处理多次付款。

RxJava使您可以将这些onClick事件转换为数据流,然后可以使用RxJava的各种运算符对其进行操作。 在此特定示例中,您可以使用debounce()运算符过滤快速连续发生的数据发射,因此,即使用户不喜欢“ 立即付款”按钮,您的应用程序也只会注册一次付款。

使用RxJava有什么好处?

我们已经看到RxJava如何在特定的应用程序中帮助您解决特定的问题,但是,它通常提供Android项目什么?

RxJava通过提供一种编写所需实现内容的方法,而不是编写应用程序必须执行的指令列表的方式,可以帮助简化代码。 例如,如果您想忽略在同一500毫秒内发生的所有数据发射,那么您应该编写:

.debounce(500, TimeUnit.MILLISECONDS)

另外,由于RxJava 几乎将所有内容都视为数据,因此它提供了一个模板,可以将其应用于各种事件:创建一个Observable,创建一个Observer,将Observer订阅到Observable,冲洗并重复。 这种公式化的方法可以使代码更加直观易懂。

Android开发人员的另一个主要好处是RxJava可以减轻Android多线程带来的痛苦。 当今的移动用户希望他们的应用程序能够执行多任务,即使这就像在后台下载数据同时又对用户输入保持响应一样简单。

Android具有用于创建和管理多个线程的多个内置解决方案,但是这些解决方案都不是特别容易实现的,它们可以快速生成复杂,冗长的代码,这些代码难以阅读且容易出错。

在RxJava中,您可以结合使用运算符和调度程序来创建和管理其他线程。 您可以使用subscribeOn运算符和调度程序轻松更改执行工作的线程。 例如,在这里我们正在安排要在新线程上执行的工作:

.subscribeOn(Schedulers.newThread())

您可以使用observeOn运算符指定将工作结果发布到observeOn 。 在这里,我们使用AndroidSchedulers.mainThread调度程序将结果发布到Android的所有重要主UI线程中,该调度程序可作为RxAndroid库的一部分使用:

.observeOn(AndroidSchedulers.mainThread())

相比于Android的内置多线程解决方案,RxJava的做法是简洁,更容易理解。

同样,您可以在我的Android RxJava 2入门文章中了解有关RxJava的工作原理以及将该库添加到项目中的好处的更多信息。

我应该使用RxJava还是RxKotlin?

由于Kotlin与Java可以100%互操作,因此您可以毫无困难地在Kotlin项目中使用大多数Java库-RxJava库也不例外。

一个专门的RxKotlin库 ,这大约是普通RxJava库Kotlin包装。 该包装器提供了扩展,可以针对Kotlin环境优化RxJava,并可以进一步减少您需要编写的样板代码。

由于您可以在Kotlin中使用RxJava而不需要RxKotlin,因此,除非另有说明,否则我们将在本文中始终使用RxJava。

在Kotlin中创建简单的观察者和可观察对象

观察者和可观察者是RxJava的构建块,所以让我们开始创建:

  • 一个简单的Observable,它响应按钮单击事件而发出短数据流。
  • 一个Observable,通过向Android Studio的Logcat打印不同的消息来对此数据做出反应。

使用您选择的设置创建一个新项目,但是请确保在出现提示时选中包括Kotlin支持复选框。 接下来,打开项目的build.gradle文件,并将RxJava库添加为项目依赖项:

dependencies {
  implementation fileTree(dir: 'libs', include: ['*.jar'])
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
  implementation 'androidx.appcompat:appcompat:1.0.0-alpha1'
  implementation 'androidx.constraintlayout:constraintlayout:1.1.0'
  implementation 'io.reactivex.rxjava2:rxjava:2.1.9'

}

然后,打开项目的activity_main.xml文件,并添加将启动数据流的按钮:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical"
  tools:context=".MainActivity" >

  <Button
      android:id="@+id/button"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Start RxJava stream" />

</LinearLayout>

创建Observable的方法有多种,但是最简单的方法之一是使用just()运算符将对象或对象列表转换为Observable。

在下面的代码中,我们将创建一个Observable( myObservable )并为其指定要发射的项目1、2、3、4和5。 我们还创建了一个Observer( myObserver ),将其订阅到myObservable ,然后让它在每次收到新的发射时向Logcat打印一条消息。

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

  private var TAG = "MainActivity"

  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)

//Start the stream when the button is clicked//

      button.setOnClickListener { startRStream() }

  }

  private fun startRStream() {

//Create an Observable//

      val myObservable = getObservable()

//Create an Observer//

      val myObserver = getObserver()

//Subscribe myObserver to myObservable//

      myObservable
              .subscribe(myObserver)
  }

  private fun getObserver(): Observer<String> {
      return object : Observer<String> {
          override fun onSubscribe(d: Disposable) {
          }

//Every time onNext is called, print the value to Android Studio’s Logcat//

          override fun onNext(s: String) {
              Log.d(TAG, "onNext: $s")
          }

//Called if an exception is thrown//

          override fun onError(e: Throwable) {
              Log.e(TAG, "onError: " + e.message)
          }

//When onComplete is called, print the following to Logcat//

          override fun onComplete() {
              Log.d(TAG, "onComplete")
          }
      }
  }

//Give myObservable some data to emit//

  private fun getObservable(): Observable<String> {
      return Observable.just("1", "2", "3", "4", "5")
  }
}

您现在可以将该应用程序进行测试:

  • 在物理Android智能手机或平板电脑或Android虚拟设备(AVD)上安装项目。
  • 单击“ 启动RxJava流”按钮。
  • 打开Android Studio的Logcat Monitor,方法是选择“ Android Monitor”选项卡(光标位于以下屏幕截图中),然后选择“ Logcat”选项卡。

此时,Observable将开始发出其数据,Observer将其消息打印到Logcat。 您的Logcat输出应如下所示:

Check Android Studios Logcat Monitor

如果您想自己尝试,可以从GitHub下载此项目

用于RxJava的Kotlin扩展

现在,我们已经了解了如何在Kotlin中建立简单的RxJava管道,让我们看看如何使用RxKotlin的扩展功能以更少的代码实现这一目标。

要使用RxKotlin库,您需要将其添加为项目依赖项:

dependencies {
  implementation fileTree(dir: 'libs', include: ['*.jar'])
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
  implementation 'androidx.appcompat:appcompat:1.0.0-alpha1'
  implementation 'androidx.constraintlayout:constraintlayout:1.1.0'
  implementation 'io.reactivex.rxjava2:rxjava:2.1.9'

//Add the following//

  implementation 'io.reactivex.rxjava2:rxkotlin:2.2.0'

}

在下面的示例中,我们使用RxKotlin的toObservable()扩展函数将List转换为Observable。 我们还使用了subscribeBy()扩展功能,因为它允许我们使用命名参数构造一个Observer,这将产生更清晰的代码。

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import io.reactivex.rxkotlin.subscribeBy
import io.reactivex.rxkotlin.toObservable
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)

//Start the stream when the button is clicked//

      button.setOnClickListener { startRStream() }

  }

  private fun startRStream() {

      val list = listOf("1", "2", "3", "4", "5")

//Apply the toObservable() extension function//

      list.toObservable()

//Construct your Observer using the subscribeBy() extension function//

              .subscribeBy(

                      onNext = { println(it) },
                      onError = { it.printStackTrace() },
                      onComplete = { println("onComplete!") }

              )
  }
}

这是您应该看到的输出:

每次调用onNext时,数据发射都会打印到Android Studios Logcat

解决RxJava的SAM歧义问题

RxKotlin还为SAM转换问题提供了重要的解决方法,当给定的Java方法上有多个SAM参数重载时,可能会发生此问题 。 这种SAM歧义性使Kotlin编译器感到困惑,因为它无法确定应该转换的接口,因此您的项目将无法编译。

当将RxJava 2.0与Kotlin一起使用时,这种SAM模糊性是一个特殊的问题,因为许多RxJava运算符都采用多种SAM兼容类型。

让我们看看实际的SAM转换问题。 在下面的代码中,我们使用zip()运算符组合两个Observable的输出:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import io.reactivex.Observable
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)

//Start the stream when the button is clicked//

      button.setOnClickListener { startRStream() }
      
  }

  private fun startRStream() {

      val numbers = Observable.range(1, 6)

      val strings = Observable.just("One", "Two", "Three",

              "Four", "Five", "Six" )

      val zipped = Observable.zip(strings, numbers) { s, n -> "$s $n" }
      zipped.subscribe(::println)
  }
}

这将导致Kotlin编译器抛出类型推断错误。 但是,RxKotlin为受影响的运算符提供了辅助方法和扩展功能,包括我们在以下代码中使用的Observables.zip()

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import io.reactivex.Observable
import io.reactivex.rxkotlin.Observables
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)

//Start the stream when the button is clicked//

      button.setOnClickListener { startRStream() }

  }

  private fun startRStream() {

      val numbers = Observable.range(1, 6)

      val strings = Observable.just("One", "Two", "Three",

              "Four", "Five", "Six" )

      val zipped = Observables.zip(strings, numbers) { s, n -> "$s $n" }
      zipped.subscribe(::println)
  }


}

这是此代码的输出:

切换到Observableszip运算符,Kotlin编译器将不再抛出类型推断错误

结论

在本教程中,我向您展示了如何在Kotlin项目中开始使用RxJava库,包括使用许多其他支持库,例如RxKotlin和RxBinding。 我们研究了如何使用扩展功能在Kotlin中创建简单的Observers和Observables,一直到针对Kotlin平台优化RxJava。

到目前为止,我们已经使用RxJava创建了简单的Observable来发射数据,并且使用Observer将这些数据打印到Android Studio的Logcat中-但这不是在现实世界中使用RxJava的方式!

在下一篇文章中,我们将研究RxJava如何帮助解决开发Android应用程序时遇到的现实问题。 我们将RxJava与Kotlin结合使用来创建经典的“ 注册”屏幕。

翻译自: https://code.tutsplus.com/tutorials/kotlin-reactive-programming-with-rxjava-and-rxkotlin--cms-31577

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值