RxJava 初学者使用指南

RxJava 入门使用指南(含 Retrofit 集成)

这篇文档是写给 刚接触 RxJava 的 Android 开发看的。
默认你会写普通的回调,比如:callback.onSuccess() / onFailure()
但对 ObservableSingle 等名字还没有概念。


一、先讲清楚几个名字(用最白话的方式)

你可以先把 RxJava 里的这些类型,理解成 “几种不同的回调习惯写法”

1.1 Observable:可以发很多次回调

  • Observable<T>:表示“可以发 0 次、1 次、很多次 数据”的东西。
  • 打个比方:
    • 传统写法:你可能会有一个 Listener,列表滚动一次就回调一次。
    • Rx 写法:改成 Observable<ScrollEvent>,每滚动一次,就 onNext(event) 一次。

你可以先记住一句话:

Observable = 可以源源不断发事件的“数据流”

1.2 Single:只会给你“一个结果”的 Observable

  • Single<T>:只会有两种结果:
    • 成功:给你 一个 T
    • 失败:给你一个错误
  • 场景:一次网络请求登录接口拉取帖子详情等:
    • 传统写法:onSuccess(User user) / onError(Throwable e)
    • Rx 写法:Single<User>

你可以把它想象成:

“只发 1 次 onNext 然后就结束的 Observable 的专门版本”

1.3 Completable:只在意“成不成”的操作

  • Completable:没有返回值,只在意:
    • 成功:onComplete()
    • 失败:onError(e)
  • 场景:
    • 点赞接口(成功/失败就行,不在乎 body 是什么)
    • 上报埋点
    • 本地写缓存

可以理解为:

“没有 onNext,只有 complete / error 的 Observable”

1.4 Maybe:可能有值,也可能没有

  • Maybe<T>:三种情况:
    • 有值:onSuccess(T)
    • 没值:onComplete()(不是错误,只是查询结果为空)
    • 出错:onError(e)
  • 场景:本地数据库查一条记录、内存缓存查找等。

1.5 Flowable:Observable 的“加强版”(带背压)

  • Flowable<T>:和 Observable 类似,也可以发很多数据,但多了“背压(Backpressure)”能力
  • “背压”白话:
    • 上游(生产者)发得太快,下游(消费者)来不及处理时,
    • 可以选择“丢掉多余的”、“只保留最新的”或者“慢慢来”等策略,避免 OOM 或卡死。
  • 场景:真正会产生大量数据的流(比如日志流、长连接推送等)。
    普通业务接口大部分用不到,初学可以先记住有这个东西就行。

1.6 Observable 的三个关键回调(看一次就懂)

observable.subscribe(
    value -> { /* onNext:每来一条数据就调一次 */ },
    error -> { /* onError:出错时调用,流结束 */ },
    () -> { /* onComplete:正常结束,没有更多数据 */ }
);
  • onNext(T value):来一条数据就调一次。
  • onError(Throwable e):发生错误,流终止。
  • onComplete():正常结束,后面不会再有数据。

一条“流”的结尾:

  • 要么是 onComplete(正常结束)
  • 要么是 onError(异常结束)
    只会二选一,不会两个都调。

二、RxJava3 基本使用(从 Observable 入门)

2.1 创建 Observable

2.1.1 just:从“已经有的值”创建流

理解方式:

  • 不用 new Observable 手写,just 帮你把几个现成的值“打包成一条流”。
Observable.just("A", "B", "C")
        .subscribe(
            s -> Log.d("TAG", "onNext: " + s),
            e -> Log.e("TAG", "onError", e),
            () -> Log.d("TAG", "onComplete")
        );
2.1.2 fromIterable:从集合创建流
List<Integer> list = Arrays.asList(1, 2, 3);
Observable.fromIterable(list)
        .subscribe(i -> Log.d("TAG", "i = " + i));
2.1.3 create:自己决定什么时候发数据

create 适合“比较底层”的封装,比如:

  • 把已有的回调形式接口,改造成 Observable:
Observable<Integer> observable = Observable.create(emitter -> {
    try {
        for (int i = 0; i < 3; i++) {
            if (emitter.isDisposed()) return;
            emitter.onNext(i);
        }
        emitter.onComplete();
    } catch (Throwable e) {
        emitter.onError(e);
    }
});

2.2 常用“操作符”(可以理解为“对这条流做加工的小函数”)

2.2.1 map:一对一转换(把 A 变成 B)
Observable.just(1, 2, 3)
        .map(i -> "num:" + i)
        .subscribe(s -> Log.d("TAG", s));
2.2.2 flatMap:一对多 / 扁平化异步
Observable.just("a", "b")
        .flatMap(s -> Observable.just(s + 1, s + 2))
        .subscribe(s -> Log.d("TAG", s));
// 输出:a1, a2, b1, b2
2.2.3 filter:只留下“我想要”的
Observable.just(1, 2, 3, 4)
        .filter(i -> i % 2 == 0)
        .subscribe(i -> Log.d("TAG", "even: " + i));
2.2.4 debounce:防抖(输入搜索框时非常常用)
RxTextView.textChanges(editText)
        .debounce(300, TimeUnit.MILLISECONDS)
        .subscribe(text -> search(text.toString()));

2.3 线程切换(非常重要,但其实就两句话)

  • subscribeOn()决定“这条流最开始在哪个线程跑”,通常用来指定“网络请求在 IO 线程”。
  • observeOn()决定“从这一行之后的回调在哪个线程跑”,通常用来切回主线程更新 UI。
Observable.just("网络请求")
        .subscribeOn(Schedulers.io())              // 上游:IO 线程
        .observeOn(AndroidSchedulers.mainThread()) // 下游:主线程
        .subscribe(result -> {
            // 这里可以安全更新 UI
        });

在 Android 里,你几乎可以一直记:
「IO 线程干活,主线程更新 UI」subscribeOn(Schedulers.io()) + observeOn(AndroidSchedulers.mainThread())

2.4 管理订阅(防止内存泄漏:谁订阅,谁负责清理)

public class MyActivity extends AppCompatActivity {

    private final CompositeDisposable composite = new CompositeDisposable();

    private void doSomething() {
        Disposable d = Observable.just(1)
                .subscribe(i -> Log.d("TAG", "i=" + i));
        composite.add(d);
    }

    @Override
    protected void onDestroy() {
        composite.clear(); // 或 dispose()
        super.onDestroy();
    }
}

三、Single / Maybe / Completable 的直观理解(对 Observable 的“精简版”)

如果你只熟悉 Observable,可以这样类比理解:

3.1 Single:一定会给你一个结果

  • 场景:网络请求获取详情、登录返回用户信息等。
  • 回调:onSuccess(T) / onError(Throwable)
Single<User> single = api.getUserDetail(userId);

single
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(
        user -> showUser(user),
        error -> showError(error)
    );

3.2 Maybe:可能有值,也可能没值

  • 场景:本地缓存查询,记录可能不存在。
  • 回调:
    • onSuccess(T):查到了
    • onComplete():没查到(但不算错)
    • onError(Throwable):真正出错,比如数据库异常

3.3 Completable:只在意成不成

  • 场景:点赞、打点、写本地日志、不关心返回体的接口。
  • 回调:onComplete() / onError(Throwable)
Completable.fromAction(() -> api.likeComment(commentId))
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(
        () -> toast("点赞成功"),
        e  -> toast("点赞失败")
    );

记忆小抄:

  • Single:“会给你一个结果的回调”
  • Maybe:“可能有结果,也可能没有的回调”
  • Completable:“只有成功/失败的回调”

四、和 Retrofit 一起用(这才是 Android 项目里最常见的用法)

4.1 添加依赖

implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
implementation "com.squareup.retrofit2:adapter-rxjava3:2.9.0"

implementation "io.reactivex.rxjava3:rxjava:3.1.8"
implementation "io.reactivex.rxjava3:rxandroid:3.0.2"

注意:RxJava3 需要 adapter-rxjava3,不要再用 RxJava2 时代的适配器,否则会类型/包名对不上。

4.2 定义 Retrofit 接口

public interface PostDetailApi {

    // 返回 Single:只发一次结果
    @GET("post/detail/v2")
    Single<PostDetailJson> postDetailV2(
            @Query("from") String from,
            @Query("pid") long postId
    );
}

4.3 创建 Retrofit + RxJava3 适配器

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.example.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
        .build();

PostDetailApi postDetailApi = retrofit.create(PostDetailApi.class);

4.4 结合线程切换进行调用(完整一条链)

public Single<PostDetailJson> getPostDetail(long pId, String from) {
    return postDetailApi.postDetailV2(from, pId)
            .subscribeOn(Schedulers.io())              // 在 IO 线程发起网络请求
            .observeOn(AndroidSchedulers.mainThread()); // 回到主线程处理结果
}

在调用处订阅:

CompositeDisposable composite = new CompositeDisposable();

private void loadPostDetail(long postId) {
    Disposable d = getPostDetail(postId, "post_detail")
            .subscribe(
                detail -> showPost(detail),
                error -> showError(error)
            );
    composite.add(d);
}

@Override
protected void onDestroy() {
    composite.clear();
    super.onDestroy();
}

这段代码和你项目里的写法是同一个思路,比如:

return postDetailApi.postDetailV2(fromObject, pId, from, fp, cp)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread());

区别只在于:这里返回 Single<PostDetailJson>,你那里可能是 Observable<PostDetailJson>
但都是:接口返回一个 Rx 类型(Single/Observable),在调用方统一指定线程和订阅逻辑。


五、小结:如果你是新手,先做到这 4 点就够了

  1. 接口请求尽量用 Single<T> 表达
    原来写 Observable<PostDetailJson> 的地方,可以慢慢改成 Single<PostDetailJson>
    看到类型就知道“这是一次请求,不是无限流”。

  2. 只关心成功/失败的操作,用 Completable
    点赞、打点、写本地日志,不需要强行塞一个 T 出来。

  3. 固定一套线程写法
    在 Android 里几乎可以一直写:
    subscribeOn(Schedulers.io()) + observeOn(AndroidSchedulers.mainThread())

  4. 统一管理订阅,避免泄漏
    使用 CompositeDisposable,在 onDestroy() 或 ViewModel 的 onCleared() 里统一 clear()

做到这些,你在项目里看 RxJava 代码、写简单封装,已经绰绰有余
后面再遇到更复杂的操作符或 Flowable,只要知道大方向,就可以随用随查了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值