Rxjava3 全新详解及常用操作符

简介

RxJava 是一个基于 Java 的响应式编程库,用于处理异步事件流和数据流。它是由 Netflix 开发并开源,现在广泛用于 Android 和 Java 后端开发。RxJava 提供了一种用于组合和处理异步数据的丰富工具集,它的核心思想是将数据流视为一系列事件,以响应事件的方式进行处理。RxJava 提供了丰富的操作符,用于处理和转换数据流。这些操作符可以帮助你执行各种操作,包括过滤、映射、合并、变换等,以便更好地处理异步数据流。

RxJava 原理

  1. Observable 和 Observer:RxJava 的核心是 Observable(可观察对象)和 Observer(观察者)。Observable 表示一个可观察的数据源,它可以发射数据项,而 Observer 用于订阅并监听这些数据项的变化。
  2. 操作符:RxJava 提供了各种操作符,用于对数据流进行转换、过滤、组合和其他处理。操作符可以将一个 Observable 转换成另一个 Observable,从而实现数据的转换和处理。
  3. 流式编程:RxJava 支持链式调用,可以将多个操作符和观察者方法连接在一起,以创建复杂的数据流处理逻辑。
  4. 异步和线程控制:RxJava 允许你轻松处理异步操作,使用 subscribeOnobserveOn 等操作符,可以指定在哪个线程上执行 Observable 和 Observer 的代码。
  5. 背压处理:RxJava 2 引入了背压处理机制,允许 Observable 控制发射的速度,以避免内存溢出和资源泄漏问题。

RxJava 在 Android 中的功能作用:

  1. 简化异步操作:RxJava 简化了异步操作,例如网络请求、数据库访问、文件读写等。你可以使用 Observable 发射异步事件,然后使用 Observer 来处理这些事件。
  2. 响应式UI:RxJava 可以在 Android UI 线程和后台线程之间建立响应式的通信,以便在 UI 上更新数据或执行操作。
  3. 处理多个观察者:RxJava 允许你轻松地将多个观察者订阅到一个 Observable,这对于多个界面元素依赖于相同数据源的情况很有用。
  4. 处理错误和异常:RxJava 提供了各种操作符,用于处理错误和异常,例如 onErrorReturnonErrorResumeNext 等,以确保应用程序能够更健壮地处理异常情况。
  5. 组合和转换数据流:RxJava 提供了丰富的操作符,用于组合和转换数据流。例如,你可以使用 zip 将多个数据流合并,或使用 map 转换数据项的类型。
  6. 事件总线:RxJava 可以用作事件总线,允许不同组件之间进行松散耦合的通信,例如通过 RxBus 发送和接收事件。
  7. 自动管理资源:RxJava 可以帮助你管理资源,例如自动释放订阅,避免内存泄漏。
  8. 测试支持:RxJava 提供了测试支持,可以轻松地测试异步操作,确保应用程序的可靠性。

Rxjava 基本组成

1. 响应式编程: RxJava 的核心思想是响应式编程,它允许你以一种响应事件的方式来处理数据流。你可以订阅一个数据流,然后定义事件处理的方式。当数据项到达时,它们会触发事件,观察者(Observer)会监听这些事件并执行相应的操作。

2. 基本组件: RxJava 的基本组件包括以下几个部分

  • Observable(可观察对象): 表示一个能够发射数据项的数据源。Observable 可以发射零个或多个数据项,以及错误或完成事件。
  • Observer(观察者): 订阅 Observable 并监听发射的事件。Observer 可以处理数据项、错误和完成事件。
  • Flowable (背压可观察对象) :和Observable使用和功能类似,区别是Flowable支持背压,Flowable操作符默认的缓存空间大小128。
  • Subscriber(订阅者): 类似于 Observer,用于订阅 Observable。
  • Operator(操作符): 用于对 Observable 发射的数据流进行变换、过滤、合并等操作。
  • Schedulers(调度器): 用于控制事件的执行线程,例如在主线程或后台线程执行。

3. 操作符: RxJava 提供了大量的操作符,用于操作和转换数据流。这些操作符包括 mapfilterflatMapzipmerge 等,允许你根据需要执行各种操作。

4. 异步和并发: RxJava 简化了异步编程,允许你轻松地处理多线程和并发操作。你可以使用 subscribeOnobserveOn 操作符来指定代码的执行线程,以避免阻塞主线程。

5. 错误处理: RxJava 提供了多种方式来处理错误,包括 onErroronErrorReturnonErrorResumeNext 等,以确保应用程序能够更健壮地处理异常情况。

6. 背压处理: RxJava 2 引入了背压处理机制,用于处理生产者和消费者之间的速率不匹配问题。背压机制允许 Observable 控制数据的发射速率,以避免内存溢出和资源泄漏。

7. 在 Android 中的应用: RxJava 在 Android 开发中广泛应用于处理异步操作,例如网络请求、数据库访问、UI事件响应等。它简化了异步编程,提高了代码的可读性和可维护性,同时提供了更好的性能和响应性。

8. 流式编程: RxJava 支持链式调用,可以将多个操作符和观察者方法连接在一起,以创建复杂的数据流处理逻辑。这使得代码更具表达力和可读性。

Rxjava使用

RxJava 的基本用法: \

  1. 创建一个 Observable,它会发射整数数据。\
  2. 创建一个观察者 Observer,用于订阅这个 Observable
  3. 使用 subscribe 方法将观察者订阅到 Observable 上,观察者会监听 Observable 发射的数据项和事件。
    //创建一个 `Observable`,它会发射整数数据。val observable = Observable.create(ObservableOnSubscribe<Int> {for (i in 1..10) {it.onNext(i)}it.onComplete()})var num: Int;var dd : Disposable? = null//创建一个观察者 `Observer`,用于订阅这个 `Observable`val observer = object:Observer<Int>{override fun onSubscribe(d: Disposable) {//当调用订阅时调用此方法dd = d}override fun onNext(t: Int) {//上游发送数据时调用此方法 即当 Observable 发射数据项时调用num = tif (num == 5){dd!!.dispose()}Log.d(TAG,"接受上游数据:$t")}override fun onError(e: Throwable) {// 当出现错误时调用}override fun onComplete() {// 当 Observable 完成时调用}}//使用subscribe方法将观察者订阅到 Observable上,观察者会监听Observable发射的数据项和事件。observable.subscribe(observer)

也可以使用方法:直接使用函数式编程,把创建后的被观察者通过订阅方法(订阅操作符)把创建观察者作为订阅方法的参数;伪代码:

    Observable.create(ObservableOnSubscribe<Int> {//上游发送数据it.onNext(1)it.onNext(3)it.onNext(5)it.onComplete()}).subscribe(object :Observer<Int>{override fun onSubscribe(d: Disposable) {}override fun onNext(t: Int) {//下游接受数据Log.i(TAG,"接受到上游数据:$t")}override fun onError(e: Throwable) {}override fun onComplete() {}})

操作符

Rxjava 的使用核心点就是各种操作符的使用;所以以下介绍一些常用的 RxJava 操作符的详细使用示例:

  • 首先操作符的分类:

    创建操作符

    1. just:创建一个发射指定数据项的 Observable。
    2. fromArray:从一个数组或可迭代对象中创建一个 Observable。
    3. create:手动创建一个 Observable。
    4. range:创建一个发射特定整数范围的 Observable。

    转换操作符

    1. map:将数据项转换为另一种类型。
    2. flatMap:将每个数据项映射为一个 Observable,然后将这些 Observables 合并成一个数据流。
    3. concatMap:类似于 flatMap,但保持原始数据项的顺序。
    4. buffer:将数据项分组为列表,并以列表的形式发射。

    过滤操作符

    1. filter:过滤掉不满足条件的数据项。
    2. distinct:过滤掉重复的数据项。
    3. take:仅发射前 N 个数据项。
    4. skip:跳过前 N 个数据项。

    组合操作符

    1. merge:合并多个 Observables 的数据流。
    2. zip:将多个 Observables 的数据项按顺序一对一地合并。
    3. combineLatest:将多个 Observables 最近的数据项合并成一个。

    辅助操作符

    1. subscribe:用于订阅 Observable 并处理数据。
    2. observeOn:指定观察者运行在特定的调度器上。
    3. subscribeOn:指定 Observable 运行在特定的调度器上。
    4. debounce:用于过滤数据流,只保留最新的数据项。
    5. delay:延迟发射数据项。

    错误处理操作符

    1. onErrorReturn:在遇到错误时发射一个默认值。
    2. onErrorResumeNext:在遇到错误时切换到另一个 Observable。
    3. retry:在遇到错误时重试操作。
创建型操作符

创建型用于创建 Observable(被观察者)实例,它们是构建数据流的起点(上游)。

1. Observable.create 这是最通用的创建型操作符。它允许你手动创建一个 Observable,你需要在其中定义数据项的发射逻辑。这个操作符通常用于创建自定义的 Observable。

val observable = Observable.create<String> { emitter ->emitter.onNext(1) //手动调用发射逻辑emitter.onNext(2)emitter.onComplete()//手动调用发射完成的逻辑
}.subscribe(object :Observer<String>{override fun onSubscribe(d: Disposable) {}override fun onNext(t: String) {Log.d("Rxjava ","下游接受到上游的数据:" + t)}override fun onError(e: Throwable) {}override fun onComplete() {}})或者使用Observer的简化版Consumer
.subscribe(object :Consumer<String>{override fun accept(t: String?) {Log.d("Rxjava","下游接受到上游的数据:$t")}})

2. Observable.just 用于创建一个发射指定数据项的 Observable。它可以发射多个数据项,然后自动完成发射数据项。

val observable = Observable.just(1, 3, 5,7)//just方法参数为可变参数,参数类型为泛型
.subscribe(object :Consumer<String>{override fun accept(t: Int) {Log.d("Rxjava","下游接受到上游的数据:$t")}})

3. Observable.fromArray 从一个数组、可迭代对象或可变参数列表中创建一个 Observable。然后自动完成发射数据项。

val numbers = arrayOf(1, 2, 3)
val observable = Observable.fromArray(numbers)
.subscribe(object :Consumer<Array<Int>>{override fun accept(t: Array<Int>?) {}})

4. Observable.fromIterable: 从一个 Iterable 对象(如 List 或 Set)中创建一个 Observable。

 val list = listOf("A", "B", "C")val observable = Observable.fromIterable(list).subscribe(object :Consumer<String>{override fun accept(t: String?) {}})     

5. Observable.interval 创建一个 Observable,定期发射一个递增的长整型数值。

Observable.interval(1, TimeUnit.SECONDS)//重载方法很多  .subscribe(object :Consumer<Long>{  override fun accept(t: Long?) {}})

6. Observable.range: 创建一个 Observable,发射一个指定范围内的整数序列。

Observable.range(1,6).subscribe(object :Consumer<Int>{override fun accept(t: Int?) {}})

7. Observable.timer 创建一个 Observable,在指定延迟后发射一个数据项。

Observable.timer(2, TimeUnit.SECONDS).subscribe(object :Consumer<Long>{override fun accept(t: Long?) {}})

这些创建型操作符用于生成不同类型的 Observable,根据需求选择合适的操作符。它们是构建数据流的起点,后续可以使用各种操作符对数据流进行变换、过滤、合并等操作,以满足具体的需求。在实际应用中,你通常会根据场景选择适当的创建型操作符来构建 Observable。

转换操作符

RxJava 的转换操作符用于对 Observable 发射的数据流进行变换、映射和操作。它们允许你以不同的方式处理数据项,以满足特定需求。

map 操作符: map 用于将 Observable 发射的每个数据项转换为另一种数据类型。它的参数是一个函数,该函数将原始数据项转换为新的数据项。

Observable.just(1, 2, 3).map(object :Function<Int,String>{override fun apply(t: Int?): String {val str = t.toString()return str}}).subscribe(object:Consumer<String>{override fun accept(t: String?) {Log.d(TAG, "Transformed: $t")}})/*subscribe {value ->Log.d(TAG, "Transformed: $value")}*/

flatMap 操作符: flatMap 用于将每个数据项映射为一个 Observable,然后将这些 Observables 合并成一个单一的数据流。这允许并发处理数据项。

Observable.just(1, 2, 3).flatMap(object:Function<Int ,Observable<String>>{override fun apply(t: Int?): Observable<String> {return Observable.just(t.toString())}})
//            flatMap { number ->
//                Observable.just(number, number * 2)
//            }.subscribe { value -> Log.d(TAG, "FlatMapped: $value") }

concatMap 操作符: concatMap 类似于 flatMap,但它保持原始数据项的顺序。它等待前一个 Observable 完成后才处理下一个。

Observable.just(1, 2, 3).concatMap(object:Function<Int ,Observable<String>>{override fun apply(t: Int?): Observable<String> {return Observable.just(t.toString())}})/*.concatMap { number ->Observable.just(number, number * 2)}*/.subscribe { value -> Log.d(TAG, "ConcatMapped: $value") }

buffer 操作符: buffer 用于将数据项分组为列表,并以列表的形式发射。你可以指定每个列表中的数据项数量。

Observable.just(1, 2, 3, 4, 5, 6).buffer(2).subscribe(object:Consumer<List<Int>>{override fun accept(t: List<Int>?) {Log.d("Rxjava","Buffered: $t")}})/*.subscribe { buffer -> println("Buffered: $buffer") }*/

groupBy 操作符: groupBy 允许你将 Observable 数据项按某个标准进行分组,然后发射多个子 Observable,每个子 Observable 包含一组具有相同标准的数据项。

 Observable.just(1, 2, 3, 4, 5, 6).groupBy(object : Function<Int, String> {override fun apply(t: Int): String {if (t!! % 2 == 0) {return "偶数"}return "奇数"}}).subscribe(object : Consumer<GroupedObservable<String, Int>> { //注意GroupedObservable<String, Int>参数的类型和Function<Int, String>反过来override fun accept(t: GroupedObservable<String, Int>) { //GroupedObservable被观察者t.subscribe(object : Consumer<Int> {override fun accept(value: Int?) {Log.d("Rxjava", "Group ${t.key}: ${value}")}})}})//lambda表达式Observable.just(1, 2, 3, 4, 5, 6).groupBy { it % 2 == 0 }.subscribe { group ->group.subscribe { value ->Log.d("Rxjava", "Group ${group.key}: $value")}}

scan 操作符: scan 用于将数据项累积成一个中间结果,然后发射这个中间结果。

Observable.just(1, 2, 3, 4, 5).scan(object :BiFunction<Int,Int,Int>{override fun apply(t1: Int, t2: Int): Int {return t1 + t2}}).subscribe(object:Consumer<Int>{override fun accept(t: Int?) {Log.d("Rxjava","Scanned: $t")}})
//                .scan { acc, value -> acc + value }
//                .subscribe { result -> Log.d("Rxjava","Scanned: $result") }打印结果:
Scanned: 1
Scanned: 3
Scanned: 6
Scanned: 10
Scanned: 15

这些转换操作符可以帮助你根据需要对数据流进行变换、映射和操作。你可以选择合适的操作符来满足具体的业务需求,以便更有效地处理异步数据流。 RxJava 提供了众多其他转换操作符,可以根据实际需求查阅文档来使用。

过滤操作符

RxJava 的过滤操作符用于从 Observable 中过滤、筛选和筛除数据项,以便只保留满足特定条件的数据项。

filter 操作符: filter 用于过滤掉不满足条件的数据项,只保留满足条件的数据项。条件由一个函数决定。

Observable.just(1, 2, 3, 4, 5, 6).filter(object:Predicate<Int>{override fun test(t: Int): Boolean {return t%2 ==0;}}).subscribe(object :Consumer<Int>{override fun accept(value: Int?) {Log.d("Rxjava","Filtered: $value")}})/* .filter { it % 2 == 0 }.subscribe { value -> Log.d("Rxjava","Filtered: $value") }*/

distinct 操作符: distinct 用于过滤掉重复的数据项,只保留第一次出现的数据项。

//lambda写法
Observable.just(1, 2, 2, 3, 4, 4, 5).distinct().subscribe { value -> println("Distinct: $value") }

distinctUntilChanged 操作符: distinctUntilChanged 用于过滤掉连续重复的数据项,只保留第一次出现的数据项。

//lambda写法
Observable.just(1, 1, 2, 2, 3, 4, 4, 5).distinctUntilChanged().subscribe { value -> println("DistinctUntilChanged: $value") }

take 操作符: take 用于仅发射前 N 个数据项,忽略其余的数据项。

Observable.just(1, 2, 3, 4, 5).take(3).subscribe { value -> println("Taken: $value") }

skip 操作符: skip 用于跳过前 N 个数据项,只发射后续的数据项。

Observable.just(1, 2, 3, 4, 5).skip(2).subscribe { value -> println("Skipped: $value") }

elementAt 操作符: elementAt 用于发射指定索引位置的数据项,忽略其他数据项。

Observable.just(1, 2, 3, 4, 5).elementAt(2).subscribe { value -> println("ElementAt: $value") }

takeLast 操作符: takeLast 用于仅发射最后 N 个数据项,忽略前面的数据项。

Observable.just(1, 2, 3, 4, 5).takeLast(3).subscribe { value -> println("TakeLast: $value") }

这些过滤操作符可以帮助你根据特定条件来过滤和筛选数据流,以满足具体的需求。你可以选择合适的操作符来处理数据流,从而仅保留需要的数据项,而忽略其他数据项。在实际应用中,过滤操作符常用于数据筛选、去重、限制数量等场景,以帮助你更有效地处理异步数据流。 RxJava 还提供了其他过滤操作符,可以根据实际需求查阅文档来使用。

组合操作符

RxJava 的组合操作符用于将多个 Observable 合并、组合或操作,以生成新的 Observable 或数据流。

  1. merge 操作符: merge 用于合并多个 Observables 的数据流,以按照发射顺序合并它们的数据项。这意味着数据项将按照它们发射的顺序合并,不考虑来源 Observable。

    kotlinCopy codeval observable1 = Observable.just(1, 2, 3)
    val observable2 = Observable.just(4, 5, 6)Observable.merge(observable1, observable2).subscribe { value -> println("Merged: $value") }
  2. concat 操作符: concat 用于合并多个 Observables 的数据流,但它保持原始 Observables 的顺序,先合并第一个 Observable 的数据,再合并第二个 Observable 的数据,以此类推。

    kotlinCopy codeval observable1 = Observable.just(1, 2, 3)
    val observable2 = Observable.just(4, 5, 6)Observable.concat(observable1, observable2).subscribe { value -> println("Concatenated: $value") }
  3. zip 操作符: zip 用于将多个 Observables 的数据项一对一地合并,生成一个新的 Observable。它会按顺序将每个 Observable 的相同索引位置的数据项合并在一起。

    kotlinCopy codeval observable1 = Observable.just("A", "B", "C")
    val observable2 = Observable.just(1, 2, 3)Observable.zip(observable1, observable2) { str, num -> "$str$num" }.subscribe { value -> println("Zipped: $value") }
  4. combineLatest 操作符: combineLatest 用于将多个 Observables 最近的数据项合并成一个新的 Observable。每当任何一个源 Observable 发射新数据,将使用最近发射的数据项来组合生成新的数据项。

    kotlinCopy codeval observable1 = Observable.interval(300, TimeUnit.MILLISECONDS).map { "A$it" }
    val observable2 = Observable.interval(200, TimeUnit.MILLISECONDS).map { "B$it" }Observable.combineLatest(observable1, observable2) { a, b -> "$a-$b" }.take(5).subscribe { value -> println("Combined: $value") }
  5. switchOnNext 操作符: switchOnNext 用于在一个 Observable 发射多个 Observables 时,切换到最新的 Observable 并发射它的数据。

    kotlinCopy codeval observables = listOf(Observable.just(1, 2, 3),Observable.just(4, 5, 6),Observable.just(7, 8, 9)
    )Observable.fromIterable(observables).switchMap { it }.subscribe { value -> println("Switched: $value") }

这些组合操作符允许你将多个 Observables 合并、组合或操作,以满足不同的数据处理需求。你可以根据具体的场景选择合适的操作符,以便有效地处理异步数据流。在实际应用中,组合操作符常用于合并多个数据源,进行数据计算和处理,以及管理多个数据流的交互。 RxJava 还提供了其他组合操作符,可以根据实际需求查阅文档来使用。

错误操作符

RxJava 的错误处理操作符用于处理 Observable 中可能出现的错误和异常情况,以确保应用程序能够更健壮地处理这些问题。

  1. onErrorReturn 操作符: onErrorReturn 用于在 Observable 遇到错误时发射一个默认值,并继续正常的数据流。

    kotlinCopy codeObservable.create<Int> { emitter ->emitter.onNext(1)emitter.onError(Exception("An error occurred"))
    }
    .onErrorReturn { error -> 0 }
    .subscribe({ value -> println("Received: $value") },{ error -> println("Error: ${error.message}") }
    )
  2. onErrorResumeNext 操作符: onErrorResumeNext 用于在 Observable 遇到错误时切换到另一个 Observable,并继续发射数据。

    kotlinCopy codeval sourceObservable = Observable.create<Int> { emitter ->emitter.onNext(1)emitter.onError(Exception("An error occurred"))
    }val fallbackObservable = Observable.just(2, 3, 4)sourceObservable.onErrorResumeNext(fallbackObservable).subscribe({ value -> println("Received: $value") },{ error -> println("Error: ${error.message}") })
  3. retry 操作符: retry 用于在 Observable 遇到错误时重试操作,指定重试次数。如果重试次数用尽仍有错误,错误会传递给观察者。

    kotlinCopy codevar attempts = 0Observable.create<Int> { emitter ->if (attempts < 3) {attempts++emitter.onError(Exception("An error occurred"))} else {emitter.onNext(1)emitter.onComplete()}
    }
    .retry(3)
    .subscribe({ value -> println("Received: $value") },{ error -> println("Error: ${error.message}") }
    )
  4. retryWhen 操作符: retryWhen 允许你自定义错误重试策略。你可以在 retryWhen 中返回一个 Observable,用于控制重试次数和时机。

    kotlinCopy codevar attempts = 0Observable.create<Int> { emitter ->if (attempts < 3) {attempts++emitter.onError(Exception("An error occurred"))} else {emitter.onNext(1)emitter.onComplete()}
    }
    .retryWhen { errors ->errors.flatMap { error ->if (attempts < 3) {Observable.timer(1, TimeUnit.SECONDS)} else {Observable.error(error)}}
    }
    .subscribe({ value -> println("Received: $value") },{ error -> println("Error: ${error.message}") }
    )
  5. onErrorComplete 操作符: onErrorComplete 用于在 Observable 遇到错误时忽略错误,不传递给观察者,直接完成 Observable。

    kotlinCopy codeObservable.create<Int> { emitter ->emitter.onNext(1)emitter.onError(Exception("An error occurred"))
    }
    .onErrorComplete()
    .subscribe({ value -> println("Received: $value") },{ error -> println("Error: ${error.message}") }
    )
    

这些错误处理操作符允许你在 Observable 遇到错误和异常情况时采取不同的处理策略,以确保你的应用程序能够更好地应对异常情况。你可以根据具体的需求选择合适的操作符,以提高应用程序的可靠性和健壮性。 RxJava 还提供了其他错误处理操作符,可以根据实际需求查阅文档来使用。

总结:以上都是同步操作,即被观察者和观察者都是在默认线程中执行(Android的主线程)

其他常用操作符

  1. subscribeOn 操作符: subscribeOn 用于指定 Observable 的创建和订阅操作运行在指定的线程。通常用于将耗时的任务移到后台线程执行,以避免阻塞主线程。

    kotlinCopy codeObservable.create<Int> { emitter ->// 在 IO 线程执行任务emitter.onNext(1)emitter.onComplete()
    }
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe { value -> println("Received on main thread: $value") }
  2. observeOn 操作符: observeOn 用于指定观察者(Observer)接收数据的线程。它允许你将数据切换到主线程,以更新 UI,或切换到其他线程执行特定操作。

    kotlinCopy codeObservable.just(1, 2, 3).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe { value -> println("Received on main thread: $value") }
  3. observeOn(io.reactivex.rxjava3.schedulers.Scheduler) 除了 Android 主线程调度器 (AndroidSchedulers.mainThread()),RxJava 还提供了其他内置的调度器,如 Schedulers.io()Schedulers.computation() 等,用于切换到不同的线程池执行任务。

    kotlinCopy codeObservable.just(1, 2, 3).subscribeOn(Schedulers.io()).observeOn(Schedulers.computation()).subscribe { value -> println("Received on computation thread: $value") }
  4. subscribeOnobserveOn 组合: 通常,你需要结合使用 subscribeOnobserveOn 来控制 Observable 的创建和订阅线程以及观察者接收数据的线程。

    kotlinCopy codeObservable.create<Int> { emitter ->// 在 IO 线程执行任务emitter.onNext(1)emitter.onComplete()
    }
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe { value -> println("Received on main thread: $value") }
  5. doOnSubscribedoOnNext 操作符: 这些操作符用于在特定事件发生时执行操作,例如,使用 doOnSubscribe 可以在订阅发生时切换线程。

    kotlinCopy codeObservable.just(1, 2, 3).doOnSubscribe { println("Subscribed on ${Thread.currentThread().name}") }.subscribeOn(Schedulers.io()).doOnNext { value -> println("Processing on ${Thread.currentThread().name}: $value") }.observeOn(AndroidSchedulers.mainThread()).subscribe { value -> println("Received on main thread: $value") }

这些线程切换操作符允许你在 RxJava 中灵活地控制数据流的线程调度,以满足不同场景下的性能和响应需求。你可以根据具体的需求和场景来选择合适的线程切换操作符,以优化应用程序的性能和用户体验。 RxJava 还提供其他线程切换操作符和自定义调度器的功能,可以根据实际需求查阅文档来使用。

躲在树皮中欧洲刺猬,苏塞克斯,英国

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/106122.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信发红包(各种红包类型)-测试用例设计

微信发红包&#xff08;各种红包类型&#xff09;

总结10.15

项目进展 登陆注册&#xff0c;连接了数据库&#xff0c;找回密码写到了通过给邮箱发送验证码&#xff0c;然后重新输入密码 项目看法 之后俩天加紧把这个登陆注册这些搞完&#xff0c;注册用到的随机生成一个账号且不重复&#xff0c;且设置一个邮箱作为之后找回密码时候的…

CVPR 2023 | 数据驱动的解释对分布外数据具有鲁棒性吗?

论文链接&#xff1a; https://arxiv.org/abs/2303.16390 代码链接&#xff1a; https://github.com/tangli-udel/DRE 01. 研究背景&#xff1a;数据驱动的解释对分布外数据具有鲁棒性吗&#xff1f; 近年来&#xff0c;将黑盒机器学习&#xff08;ML&#xff09;模型用于高风…

CentOS 7 编译安装Boost

1、前提条件 linux平台/CentOS 7 下要编译安装Boost除gcc和gcc-c之外&#xff0c;还需要两个开发库&#xff1a;bzip2-devel 和python-devel &#xff0c;因此在安装前应该先保证这两个库已经安装。 安装指令: yum install bzip2 bzip2-devel bzip2-libs python-devel Cent…

zookeeper源码学习笔记(一)

一、缘起 1、CP还是AP 作为一个在大数据行业工作了7&#xff5e;8年的老兵&#xff0c;在被问到zookeeper和CAP时&#xff0c;竟然有些恍惚&#xff0c;AP还是CP&#xff1f; 看了一些博文&#xff0c;答案几乎都是CP&#xff1f; zookeeper的实现中&#xff0c;P是一定的&…

低代码提速应用开发

低代码介绍 低代码平台是指一种能够帮助企业快速交付业务应用的平台。自2000年以来&#xff0c;低代码市场一直充斥着40大大小小的各种玩家&#xff0c;比如国外的Appian、K2、Pega Systems、Salesforce和Ultimus&#xff0c;国内的H3 BPM。 2015年以后&#xff0c;这个市场更是…

2023年厦门市高等职业院校技能竞赛软件测试竞赛规程

2023年厦门市高等职业院校技能竞赛 软件测试竞赛规程 一、赛项名称 赛项名称&#xff1a;软件测试 竞赛形式&#xff1a;团体赛 赛项专业大类&#xff1a;电子信息 二、竞赛目的 &#xff08;一&#xff09;检验教学成效 本赛项竞赛内容以《国家职业教育改革实施方案》为设计方…

Docker逃逸---procfs文件挂载

一、产生原因 将宿主机/proc目录挂载进了容器&#xff0c;而该目录内的/proc/sys/kernel/core_pattern文件是负责进程奔溃时内存数据转储的&#xff0c;当第一个字符是| 管道符时&#xff0c;后面的部分会以命令行的方式进行解析并运行&#xff0c;攻击者可以将恶意文件写入该…

【Python数据分析工具】

文章目录 概要整体架构流程技术名词解释 概要 数据分析是一种通过收集、处理、分析和解释大量数据&#xff0c;以发现有价值信息、洞察趋势、制定决策并解决问题的过程。在现代科技和互联网的推动下&#xff0c;数据分析变得日益重要。它不仅仅是对数字和图表的简单解释&#…

MacOS ventura跳过配置锁

Macbook pro 2021跳配置锁 1.什么是配置锁&#xff1f; 配置锁顾名思义就是美国一些企业和公司向苹果工公司定制采购的机器&#xff0c;这些机器一般供应内部员工使用&#xff0c;这种机器和正常机没有什么区别&#xff0c;也是无锁三网机器&#xff0c;功能和正常机器一摸一…

如何用精准测试来搞垮团队?

测试行业每年会冒出来一些新鲜词&#xff1a;混沌工程、精准测试、AI测试…… 这些新概念、新技术让我们感到很焦虑&#xff0c;逼着自己去学习和了解这些新玩意&#xff0c;担心哪一天被淘汰掉。 以至于给我这样的错觉&#xff0c;当「回归测试」、「精准测试」这两个词摆在一…

解决git在window11操作很慢,占用很大cpu的问题

【git在window11操作很慢&#xff0c;占用很大cpu&#xff0c;最后也执行失败】 在谷歌输入&#xff1a;git very slow in window 11。通过下面链接终于找到了解决方案&#xff1a; https://www.reddit.com/r/vscode/comments/sulebx/slow_git_in_wsl_after_updating_to_window…

怒刷LeetCode的第26天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一&#xff1a;动态规划 第二题 题目来源 题目内容 解决方法 方法一&#xff1a;有限状态自动机 方法二&#xff1a;正则表达式 第三题 题目来源 题目内容 解决方法 方法一&#xff1a;从最后一位向前遍历 方法二…

测试除了点点点,还有哪些内容呢?

今天和一个网友讨论了一下关于互联网行业中测试的情况&#xff0c;希望能够了解现在的互联网行业主要的测试工作内容。小编根据以往的工作经历和经验情况&#xff0c;来做一个总结和整理。 1、岗位分类 现在的岗位划分主要是分为两大类&#xff1a;测试工程师 和 测试开发工程…

matlab相机标定实验

实验原理 1. 相机标定坐标系 相机的参数对目标的识别、定位精度有很大的影响&#xff0c;相机标定就是为了求出相机的内外参数。标定中有3个不同层次的坐标系&#xff1a;世界坐标系、相机坐标系和图像坐标系&#xff08;图像物理坐标系和图像像素坐标系&#xff09;。世界坐…

数据结构--》掌握数据结构中的排序算法

当我们面对海量数据时&#xff0c;如何高效地将其排序是数据结构领域中一个重要的问题。排序算法作为其中的关键部分&#xff0c;扮演着至关重要的角色。 无论你是初学者还是进阶者&#xff0c;本文将为你提供简单易懂、实用可行的知识点&#xff0c;帮助你更好地掌握排序算法在…

pdf怎么压缩?pdf文件缩小的方法在这里

PDF文件由于其跨平台、可打印性强等特点&#xff0c;成为了我们日常工作中经常使用的一种文件格式。然而&#xff0c;这种格式的文件有时候会因为过于庞大而给我们的存储和传输带来困扰&#xff0c;其实&#xff0c;这种情况只需要通过一些工具对PDF文件进行压缩&#xff0c;即…

【RocketMQ系列二】通过docker部署单机RocketMQ

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…

小程序uView2.X框架upload组件上传方法总结+避坑

呈现效果: 1.1单图片上传 1.2多图片上传 前言:相信很多人写小程序会用到uView框架,总体感觉还算OK吧,只能这么说,肯定也会遇到图片视频上传,如果用到这个upload组件相信你,肯定遇到各种各样的问题,这是我个人总结的单图片和多图片上传方法. uView2.X框架:uView 2.0 - 全面兼容…

4.Python-用Python,Ajax实现MySQL数据库的新增数据

题记 用python&#xff0c;ajax实现mysql数据库的新增数据。以下是一个简单的实例和操作过程。 安装flask模块 pip install flask 安装mysql.connector模块 pip install mysql-connector-python 编写app.py文件 app.py文件如下&#xff1a; 块引用可能显示不完整&#x…