4 interfaces of Flow
1. Publisher (data release)
public static interface Publisher<T> {
public void subscribe(Subscriber<? super T> subscriber);
}
- subscribe: receiving subscribers, data streamers
2. Subscriber (terminal operation)
- onSubscribe: After the subscriber is received by the publisher, notify the subscriber that the subscription is successful
- onNext: data flow Sink
- onError: the flow direction when an error occurs
- onComplete: the flow direction when the data is executed
public static interface Subscriber<T> {
public void onSubscribe(Subscription subscription);
public void onNext(T item);
public void onError(Throwable throwable);
public void onComplete();
}
3. Subscription subscription (data request, cancellation)
- request: Request data + number to solve data congestion
- cancel: cancel the subscription, the data is no longer needed
public static interface Subscription {
public void request(long n);
public void cancel();
}
4. Processor processor (intermediate operation)
- Both Subscriber and Publisher, consume and deliver data
public static interface Processor<T,R> extends Subscriber<T>, Publisher<R> {
}
Publisher-Processor-Subscriber operation process
- Green: subscription process, Subscriber-Publisher upward relationship
- Black: SUBSCRIBE SUCCESSFUL, Publisher-Subscriber Downward Relationship
- Blue: data request, Subscriber-Publisher up relationship
- Red: data distribution, Publisher-Subscriber downward relationship
Example: complete a series of actions, data delivery -> filter by condition -> data conversion -> data consumption
publisher
- Receive Spliterator and complete data delivery (T)
public class FlowPublisher<T> implements Flow.Publisher<T>, Flow.Subscription {
private final Spliterator<T> spliterator;
private Flow.Subscriber<? super T> subscriber;
private boolean completed = false;
private boolean canceled = false;
public FlowPublisher(@NonNull Spliterator<T> spliterator) {
this.spliterator = spliterator;
}
@Override
public void subscribe(Flow.Subscriber<? super T> subscriber) {
this.subscriber = subscriber;
this.subscriber.onSubscribe(this);
}
@Override
public void request(long n) {
//已完成或已取消,则不再下发消息
if(completed || canceled) {
return;
}
//数据消息下发完,则下发onComplete消息
long size = spliterator.getExactSizeIfKnown();
if(size == 0) {
completed = true;
subscriber.onComplete();
return;
}
//下发数据消息
for(long i=Math.min(n, size); i>0; i--) {
spliterator.tryAdvance(subscriber::onNext);
}
}
@Override
public void cancel() {
canceled = true;
//取消后下发onComplete消息
if(!completed) {
subscriber.onComplete();
}
}
}
Processor: filter operation
- Receive Predicate and complete data filtering (T->T). If the data is filtered, continue to request upstream until the number of downstream requests is satisfied or the distribution is completed
public class FilterProcessor<T> implements Flow.Processor<T, T>, Flow.Subscription {
private final Predicate<T> predicate;
private Flow.Subscriber<? super T> subscriber;
private Flow.Subscription subscription;
private long requestCount;
private long leftCount;
public FilterProcessor(@NonNull Predicate<T> predicate) {
this.predicate = predicate;
}
@Override
public void subscribe(Flow.Subscriber<? super T> subscriber) {
this.subscriber = subscriber;
this.subscriber.onSubscribe(this);
}
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
}
@Override
public void onNext(T item) {
requestCount--;
if(predicate.test(item)) {
subscriber.onNext(item);
} else {
leftCount++;
}
if(requestCount == 0 && leftCount > 0) {
request(leftCount);
}
}
@Override
public void onError(Throwable throwable) {
subscriber.onError(throwable);
}
@Override
public void onComplete() {
subscriber.onComplete();
}
@Override
public void request(long n) {
leftCount = 0;
requestCount = n;
subscription.request(n);
}
@Override
public void cancel() {
subscription.cancel();
}
}
Processor: mapping operation
- Receive Function and complete data conversion (P->N)
public class MappingProcessor<P, N> implements Flow.Processor<P, N> {
private final Function<P, N> function;
private Flow.Subscriber<? super N> subscriber;
private Flow.Subscription subscription;
public MappingProcessor(@NonNull Function<P, N> function) {
this.function = function;
}
@Override
public void subscribe(Flow.Subscriber<? super N> subscriber) {
this.subscriber = subscriber;
this.subscriber.onSubscribe(subscription);
}
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
}
@Override
public void onNext(P item) {
subscriber.onNext(function.apply(item));
}
@Override
public void onError(Throwable throwable) {
subscriber.onError(throwable);
}
@Override
public void onComplete() {
subscriber.onComplete();
}
}
Subscriber:TerminalOp
- Receive Consumer, complete consumption (T)
public class FlowSubscriber<T> implements Flow.Subscriber<T> {
private final Consumer<T> consumer;
private Flow.Subscription subscription;
private boolean completed = false;
private long requestCount;
private static final long REQUEST_COUNT = 3;
public FlowSubscriber(@NonNull Consumer<T> consumer) {
this.consumer = consumer;
}
@Override
public void onSubscribe(Flow.Subscription subscription) {
requestCount = REQUEST_COUNT;
this.subscription = subscription;
this.subscription.request(requestCount);
}
@Override
public void onNext(T item) {
requestCount--;
consumer.accept(item);
if(requestCount == 0 && !completed) {
requestCount = REQUEST_COUNT;
subscription.request(requestCount);
}
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
requestCount = 0;
completed = true;
}
}
FlowHelper
- Connect FlowPublisher, FilterProcessor, MappingProcessor, and FlowSubscriber in series to complete the chain operation
public class FlowHelper<T> {
private Flow.Publisher<T> publisher;
public static <E> FlowHelper<E> flow(@NonNull Spliterator<E> spliterator) {
return new FlowHelper<>(new FlowPublisher<>(spliterator));
}
private FlowHelper(@NonNull Flow.Publisher<T> publisher) {
this.publisher = publisher;
}
public FlowHelper<T> filter(@NonNull Predicate<T> predicate) {
FilterProcessor<T> p = new FilterProcessor<>(predicate);
publisher.subscribe(p);
publisher = p;
return this;
}
public <R> FlowHelper<R> mapping(@NonNull Function<T, R> function) {
MappingProcessor<T, R> p = new MappingProcessor<>(function);
publisher.subscribe(p);
return new FlowHelper<>(p);
}
public void accept(@NonNull Consumer<T> consumer) {
FlowSubscriber<T> s = new FlowSubscriber<>(consumer);
publisher.subscribe(s);
}
}
FlowTest test
- Data Generation Spliterator
- Data filtering filter: filter out non-numeric strings
- Data conversion mapping: String ---> FlowBean
- Data consumption: output Log, display result: 13689
public class FlowTest {
private final Pattern pattern;
public FlowTest() {
pattern = Pattern.compile("[0-9]*");
}
public void testFlow() {
List<String> list = List.of("1", "2a", "3", "4b", "5c", "6", "7d", "8", "9");
FlowHelper.flow(list.spliterator())
.filter(v -> pattern.matcher(v).matches())
.mapping(FlowBean::new)
.accept(FlowBean::print);
}
static class FlowBean {
final String result;
public FlowBean(String result) {
this.result = result;
}
public void print() {
Log.d("FlowTest", result);
}
}
}