Subscriber
- 一、概述
- 二、核心方法
-
- [2.1、void onSubscribe(@NonNull Subscription s)](#2.1、void onSubscribe(@NonNull Subscription s))
- [2.2、void onNext(@NonNull T t)](#2.2、void onNext(@NonNull T t))
- [2.3、void onError(@NonNull Throwable t)](#2.3、void onError(@NonNull Throwable t))
- [2.4、void onComplete()](#2.4、void onComplete())
- [三、与 Subscription 的交互模式](#三、与 Subscription 的交互模式)
- 四、简化形式
-
- [4.1、使用 Lambda 的简化订阅](#4.1、使用 Lambda 的简化订阅)
- [4.2、使用 subscribeWith()获取 Subscriber 实例](#4.2、使用 subscribeWith()获取 Subscriber 实例)
- 五、内置的Subscriber实现
- 六、注意事项
一、概述
在 RxJava 2 中,Subscriber 是用于订阅 Flowable 数据流的核心消费者接口。它是实现背压(Backpressure) 机制的关键,与 Subscription对象协同工作,实现下游对上游数据的主动拉取控制。
java
public interface Subscriber<T> {
// 关键方法
void onSubscribe(@NonNull Subscription s);
void onNext(@NonNull T t);
void onError(@NonNull Throwable t);
void onComplete();
}
Subscriber具备了Observer的所有能力,并增加了关键的 onSubscribe(Subscription s)方法。
二、核心方法
2.1、void onSubscribe(@NonNull Subscription s)
这是 Subscriber独有的、最重要的方法,也是与 Observer的关键区别。
- 调用时机:在订阅建立后,任何 onNext、onError或 onComplete被调用之前,第一个被调用的方法。
- 参数 Subscription s:这是上游(Flowable)传递给下游(Subscriber)的控制句柄。
- 必须执行的操作:在此方法中,你必须通过 s.request(long n)来请求数据。如果你不调用 request(),将永远不会收到任何数据!
典型用法:
java
@Override
public void onSubscribe(@NonNull Subscription s) {
this.subscription = s; // 保存起来供后续使用
// 必须请求数据!
s.request(1); // 请求第一个数据
// 或者
s.request(Long.MAX_VALUE); // 请求所有数据(关闭背压)
}
2.2、void onNext(@NonNull T t)
- 作用:处理上游发出的数据项。
- 触发条件:仅当通过 Subscription.request(n)请求了数据,且上游有数据可发时。
- 重要约束:在 onNext方法内部,你可以再次调用 subscription.request(n) 来请求更多数据,实现拉取式消费模式。
2.3、void onError(@NonNull Throwable t)
- 作用:处理流中的错误。调用后,流终止,不会再调用 onNext或 onComplete。
- 触发条件:上游发生错误,或下游在 onNext中抛出异常。
2.4、void onComplete()
- 作用:处理流正常完成。调用后,流终止。
- 触发条件:上游已发射完所有数据。
三、与 Subscription 的交互模式
3.1、一次性请求所有数据(关闭背压)
java
Flowable.range(1, 1000)
.subscribe(new Subscriber<Integer>() {
private Subscription subscription;
@Override
public void onSubscribe(Subscription s) {
this.subscription = s;
s.request(Long.MAX_VALUE); // 一次性请求所有,关闭背压
}
@Override
public void onNext(Integer integer) {
// 处理数据,无需再请求
System.out.println(integer);
}
@Override public void onError(Throwable t) { }
@Override public void onComplete() { }
});
3.2、拉取式消费(精确控制)
java
Flowable.range(1, 1000)
.subscribe(new Subscriber<Integer>() {
private Subscription subscription;
private int processed = 0;
@Override
public void onSubscribe(Subscription s) {
this.subscription = s;
s.request(10); // 初始请求10个
}
@Override
public void onNext(Integer integer) {
// 处理数据
process(integer);
processed++;
// 每处理5个数据,再请求5个
if (processed % 5 == 0) {
subscription.request(5);
}
// 如果处理了足够多,可以取消
if (processed >= 100) {
subscription.cancel();
}
}
@Override public void onError(Throwable t) { }
@Override public void onComplete() { }
});
3.3、异步处理与请求
java
Flowable.interval(10, TimeUnit.MILLISECONDS)
.subscribe(new Subscriber<Long>() {
private Subscription subscription;
private final ExecutorService executor = Executors.newSingleThreadExecutor();
@Override
public void onSubscribe(Subscription s) {
this.subscription = s;
s.request(1); // 只请求一个,处理完再请求下一个
}
@Override
public void onNext(Long item) {
// 异步处理,不阻塞 onNext 调用
executor.submit(() -> {
processItem(item); // 耗时处理
// 处理完成后,在异步线程中请求下一个
subscription.request(1);
});
}
@Override public void onError(Throwable t) { executor.shutdown(); }
@Override public void onComplete() { executor.shutdown(); }
});
四、简化形式
4.1、使用 Lambda 的简化订阅
java
Flowable.range(1, 10)
.subscribe(
item -> System.out.println("收到: " + item), // onNext
error -> error.printStackTrace(), // onError
() -> System.out.println("完成"), // onComplete
subscription -> {
// 这个参数就是 onSubscribe 接收的 Subscription!
// 默认实现会调用 subscription.request(Long.MAX_VALUE)
// 你可以自定义请求策略
subscription.request(5); // 只请求5个
}
);
4.2、使用 subscribeWith()获取 Subscriber 实例
java
Subscriber<Integer> mySubscriber = Flowable.range(1, 10)
.subscribeWith(new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);
}
@Override
public void onNext(Integer integer) {
System.out.println(integer);
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("完成");
}
});
// 可以稍后取消
// mySubscriber 实际上就是 DisposableSubscriber 或类似实现
五、内置的Subscriber实现
- DisposableSubscriber
java
DisposableSubscriber<Integer> subscriber = new DisposableSubscriber<Integer>() {
@Override public void onNext(Integer t) { System.out.println(t); }
@Override public void onError(Throwable t) { t.printStackTrace(); }
@Override public void onComplete() { System.out.println("完成"); }
};
Flowable.range(1, 10).subscribe(subscriber);
// 可以通过 subscriber.dispose() 取消
- ResourceSubscriber:支持资源管理的 Subscriber。
- DefaultSubscriber:基础的 Subscriber实现。
六、注意事项
- 必须调用 request():这是最重要的规则。忘记调用 request()是最常见的错误。
- request()是累加的:
java
// 以下代码总共请求了 15 个数据
subscription.request(10);
subscription.request(5); // 不是"再要5个",而是"总共要15个"
- request()的调用位置:
- 可以在 onSubscribe中调用(初始请求)
- 可以在 onNext中调用(拉取更多)
- 不要在 onError或 onComplete之后调用
- 可以从任何线程调用(线程安全)
- 正确处理取消:
- 调用 subscription.cancel()后,应停止调用 request()
- 在 onError或 onComplete后,订阅自动结束,无需再调用 cancel()
- 避免在 onNext中阻塞:
如果 onNext处理很慢,应该使用拉取模式(处理完一个再请求下一个),或使用异步处理。 - 资源清理:对于需要资源管理的场景(如数据库连接),考虑使用 ResourceSubscriber或在 onError/onComplete中清理资源。
java
Flowable.create(emitter -> {
// 快速生产数据
for (int i = 0; i < 1000; i++) {
if (emitter.isCancelled()) break; // 检查是否被取消
emitter.onNext(i);
}
emitter.onComplete();
}, BackpressureStrategy.BUFFER) // 缓冲策略
.subscribe(new Subscriber<Integer>() {
private Subscription subscription;
private final int BATCH_SIZE = 10;
@Override
public void onSubscribe(Subscription s) {
this.subscription = s;
s.request(BATCH_SIZE); // 初始请求10个
}
@Override
public void onNext(Integer integer) {
System.out.println("处理: " + integer);
// 模拟处理时间
try { Thread.sleep(100); } catch (InterruptedException e) { }
// 每处理完一个,检查是否需要请求更多
// 这里实现一个简单的批处理:当处理完一批后请求下一批
if (integer % BATCH_SIZE == BATCH_SIZE - 1) {
subscription.request(BATCH_SIZE);
}
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("所有数据处理完成");
}
});