RxJava 入门使用指南(含 Retrofit 集成)
这篇文档是写给 刚接触 RxJava 的 Android 开发看的。
默认你会写普通的回调,比如:callback.onSuccess()/onFailure(),
但对Observable、Single等名字还没有概念。
一、先讲清楚几个名字(用最白话的方式)
你可以先把 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 点就够了
-
接口请求尽量用
Single<T>表达
原来写Observable<PostDetailJson>的地方,可以慢慢改成Single<PostDetailJson>,
看到类型就知道“这是一次请求,不是无限流”。 -
只关心成功/失败的操作,用
Completable
点赞、打点、写本地日志,不需要强行塞一个T出来。 -
固定一套线程写法
在 Android 里几乎可以一直写:
subscribeOn(Schedulers.io())+observeOn(AndroidSchedulers.mainThread())。 -
统一管理订阅,避免泄漏
使用CompositeDisposable,在onDestroy()或 ViewModel 的onCleared()里统一clear()。
做到这些,你在项目里看 RxJava 代码、写简单封装,已经绰绰有余。
后面再遇到更复杂的操作符或 Flowable,只要知道大方向,就可以随用随查了。

987

被折叠的 条评论
为什么被折叠?



