RxJava的简单例子

RxAndroid 是基于 RxJava 的一个库,它专门为 Android 平台提供了方便的功能,使得在 Android 应用中处理异步事件变得更简单。下面我将提供一个简单的 RxAndroid 示例,展示如何使用它来执行异步任务并更新 UI。

首先,确保在你的 Android 项目的 build.gradle 文件中添加了 RxAndroid 和 RxJava 的依赖:

arduino 复制代码
groovyCopy code
dependencies {
    implementation 'io.reactivex.rxjava3:rxjava:3.1.3'
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
}

以下是一个简单的使用 RxAndroid 的示例,这个例子中我们将在后台线程中创建数据,然后在主线程中更新 UI:

scala 复制代码
javaCopy code
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;

public class MainActivity extends AppCompatActivity {

    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.text_view);

        // 创建 Observable
        Observable<String> observable = Observable.create(emitter -> {
            try {
                // 模拟耗时的任务
                Thread.sleep(2000);
                emitter.onNext("Hello from RxAndroid");
                emitter.onComplete();
            } catch (InterruptedException e) {
                emitter.onError(e);
            }
        });

        // 订阅 Observable
        observable
            .subscribeOn(Schedulers.io()) // 指定上游操作在 IO 线程执行
            .observeOn(AndroidSchedulers.mainThread()) // 指定下游操作在主线程执行
            .subscribe(this::updateText, this::handleError);
    }

    private void updateText(String text) {
        textView.setText(text);
    }

    private void handleError(Throwable throwable) {
        textView.setText("Error: " + throwable.getMessage());
    }
}

在这个例子中:

  • 我们创建了一个 Observable,它在被订阅时执行一个耗时操作(这里是线程休眠)。
  • 使用 subscribeOn(Schedulers.io()) 指定 Observable 的生成操作应该在 I/O 线程(后台线程)上执行。
  • 使用 observeOn(AndroidSchedulers.mainThread()) 指定在主线程上观察结果,这允许我们安全地更新 UI。
  • subscribe 方法接受两个参数,一个是处理正常数据的 updateText 方法,另一个是处理错误的 handleError 方法。

这个示例展示了 RxAndroid 的基本使用方法,通过简单的线程控制和数据流管理,使得在 Android 中进行异步编程变得更加直观和易于管理。

增加多个订阅

如果你希望两个订阅者顺序执行,即确保第一个订阅者完成后第二个订阅者开始处理数据,你可以使用 RxJava 中的 concatMapflatMap 或其他合适的操作符来管理流的顺序。这里,我将使用一个简单的方式来展示如何实现顺序执行的订阅者。

在这个例子中,我们将不再为每个订阅者分别创建 Observable 实例,而是通过链式调用保证顺序:

arduino 复制代码
javaCopy code
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private TextView textView2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.text_view);
        textView2 = findViewById(R.id.text_view2);

        // 创建一个 Observable
        Observable<String> observable = Observable.create(emitter -> {
            try {
                // 模拟耗时的任务
                Thread.sleep(2000);
                emitter.onNext("Initial data");
                emitter.onComplete();
            } catch (InterruptedException e) {
                emitter.onError(e);
            }
        });

        // 第一个订阅者执行,并在其 onComplete 中启动第二个订阅者
        observable
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnNext(this::updateText)
            .doOnComplete(() -> {
                // 在第一个订阅者完成后执行第二个订阅者
                observable
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(this::updateTextSecond, this::handleError);
            })
            .subscribe(this::updateText, this::handleError);
    }

    private void updateText(String text) {
        textView.setText(text + " (First Subscriber)");
    }

    private void updateTextSecond(String text) {
        textView2.setText(text + " (Second Subscriber)");
    }

    private void handleError(Throwable throwable) {
        textView.setText("Error: " + throwable.getMessage());
        textView2.setText("Error: " + throwable.getMessage());
    }
}

在这个例子中:

  • 第一个订阅者使用 .doOnNext().doOnComplete() 来执行任务和设置第二个订阅者的启动。
  • .doOnComplete() 操作符被用来在第一个订阅者的任务完全完成后,启动第二个订阅者的任务。
  • 这样的设置确保了第二个订阅者的数据处理完全在第一个订阅者处理完毕后才开始。

这种方式适合当你需要根据第一个订阅者的结果来决定是否以及如何继续进行第二个订阅者的操作。注意,所有的错误处理和线程调度都应该根据具体需求调整以确保应用的响应性和正确性。

切换不同的线程

在 RxJava 和 RxAndroid 中,.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) 这两句非常关键,它们定义了操作的线程环境,分别控制数据流的产生(上游)和消费(下游)发生在哪个线程。这是处理异步操作和线程管理的基本方式。

.subscribeOn(Schedulers.io())

  • subscribeOn 方法用于指定 Observable 创建数据事件的线程,或者说是操作流中的数据产生(上游操作)应该在哪个线程执行。
  • Schedulers.io() 是 RxJava 提供的一个调度器,它适用于I/O操作(如文件读写、数据库操作、网络信息交换等)。这个调度器背后是一个无界线程池,可以根据需要创建新线程,适合执行块状、耗时的I/O操作。
  • 无论你在哪里调用 .subscribeOn(),它总是影响整个链中的源头Observable的执行线程。也就是说,整个数据流的生成始终在指定的线程中执行,不受后续操作符的影响。

.observeOn(AndroidSchedulers.mainThread())

  • observeOn 方法用于指定一个 Observable 发射出来的数据在哪个线程上被消费。它改变的是在它之后的操作所在的线程,即操作流中的数据消费(下游操作)应该在哪个线程执行。
  • AndroidSchedulers.mainThread() 是 RxAndroid 提供的一个调度器,专门指定操作在 Android 主线程(UI线程)上执行。这对于需要更新UI的操作非常重要,因为在Android中,UI操作(如设置控件的文本或可见性)必须在主线程中进行。
  • 不同于 subscribeOnobserveOn 可以在链中被多次调用,每次调用都可以改变下游操作的线程。这允许在数据流的不同阶段进行线程切换,例如先在I/O线程中处理数据,然后切换回主线程来更新UI。

例子

考虑一个简单的数据流:

less 复制代码
javaCopy code
Observable.just("Hello, world!")
    .subscribeOn(Schedulers.io()) // 指定数据流生成在I/O线程
    .map(s -> s + " - from I/O thread") // 这个操作在I/O线程执行
    .observeOn(AndroidSchedulers.mainThread()) // 切换到主线程
    .map(s -> s + " - on main thread") // 这个操作在主线程执行
    .subscribe(System.out::println); // 订阅操作也在主线程执行

在这个数据流中,数据的产生和初步处理发生在 I/O 线程,但之后通过 observeOn 切换到了主线程,以执行最终的数据处理和输出。这种模式非常适合处理那些需要在背景线程中加载数据但在前台线程更新UI的常见场景。

相关推荐
二十雨辰25 分钟前
[uni-app]小兔鲜-04推荐+分类+详情
前端·javascript·uni-app
霸王蟹1 小时前
Vue3 项目中为啥不需要根标签了?
前端·javascript·vue.js·笔记·学习
小白求学11 小时前
CSS计数器
前端·css
Anita_Sun1 小时前
🌈 Git 全攻略 - Git 的初始设置 ✨
前端
lucifer3112 小时前
深入解析 React 组件封装 —— 从业务需求到性能优化
前端·react.js
等什么君!2 小时前
复习HTML(进阶)
前端·html
儒雅的烤地瓜2 小时前
JS | 如何解决ajax无法后退的问题?
前端·javascript·ajax·pushstate·popstate事件·replacestate
觉醒法师2 小时前
Vue3+TS项目 - ref和useTemplateRef获取组件实例
开发语言·前端·javascript
老章学编程i2 小时前
Vue工程化开发
开发语言·前端·javascript·vue.js·前端框架
思考的橙子2 小时前
前端初识之一
前端