rxjava 观察者模式
“ RxJava是Reactive Extensions的Java VM实现:一个用于通过使用可观察序列来组成异步和基于事件的程序的库。” 由RxJava开发人员开发。
这就对了。 基本上,它允许您遵循React式编程范例。
本文的目的是向您介绍Observable 。 为此,我将带您了解一个我使用Observable遇到并受益的简单用例。
用例:
使用ProcessBuilder生成外部流程,并使用Observable观察流程输出。
如果不使用RxJava,我将首先编写完整的程序,然后进行解释。 然后进行React式编程。
实现1:使用Java Consumer的常规方法
package io.convert2pdf.commons.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.function.Consumer;
public class RxJavaObservableProcess {
ProcessBuilder processBuilder = null ;
Process process = null ;
Consumer<String> inputConsumer;
Consumer<String> errorConsumer;
Consumer<Void> completeConsumer;
public RxJavaObservableProcess (List<String> command, Consumer<String> inputConsumer, Consumer<String> errorConsumer, Consumer<Void> completeConsumer) {
processBuilder = new ProcessBuilder(command);
this .inputConsumer = inputConsumer;
this .errorConsumer = errorConsumer;
this .completeConsumer = completeConsumer;
}
public void start () throws Exception {
process = processBuilder.start();
readInputStream(process);
readErrorStream(process);
process.waitFor();
}
private void readInputStream (Process process) {
new Thread(() -> {
BufferedReader br = new BufferedReader( new InputStreamReader(process.getInputStream()));
String line = null ;
try {
while ((line = br.readLine()) != null ) {
this .inputConsumer.accept(line);
}
this .completeConsumer.accept( null );
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
private void readErrorStream (Process process) {
new Thread(() -> {
BufferedReader br = new BufferedReader( new InputStreamReader(process.getErrorStream()));
String line = null ;
try {
while ((line = br.readLine()) != null ) {
this .errorConsumer.accept(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
public static void main (String[] args) throws Exception {
RxJavaObservableProcess process = new RxJavaObservableProcess(
List.of( "tasklist" ),
(input) -> System.out.println( "Input: " + input),
(error) -> System.out.println( "Error: " + error),
(complete) -> System.out.println( "Complete: " + complete)
);
process.start();
}
}
注意:如果在Unix上运行此命令,请将List.of(“ tasklist”)更改为List.of(“ ps”,“ aux”)
说明:
在主方法上,我初始化RxJavaObservableProcess,它接受4个参数
- 命令。 在这种情况下,我只想在Windows笔记本电脑上获取当前正在运行的进程。
- 输入流使用者。 只要有输入线可用,就会被呼叫的使用者。
- 错误流使用者。 有错误线可用时被调用的使用者。
- 完整的国家消费者。 我添加了该使用者,以便当您使用RxJava阅读代码时,可以在它们之间建立连接。
我在start方法上创建具有给定参数的Process,并分别在readInputStream和readErrorStream方法上读取输入流和错误流。 读取输入/错误流是一项阻塞操作,因此我在单独的线程中进行处理。
在每个流读取方法中,我使用BufferedReader读取一行并将其写入使用者。 在读取输入流结束时,我使用null调用completeConsumer ,以使用户知道该过程已完成。
这是一个简单的任务,但是编写它花费了很多代码。 另外,我必须事先传递所有使用者,以便可以在调用阻塞调用process.waitFor()之前将它们附加到相应的流。
这不是一个不好的程序,我实际上没有任何问题。 但是,我认为React式编程范例可以帮助我使其更好。
实施2:使用RxJava
package io.convert2pdf.commons.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.subjects.ReplaySubject;
public class RxJavaObservableProcessV2 {
ProcessBuilder processBuilder = null ;
Process process = null ;
ReplaySubject<String> processInputs = ReplaySubject.create();
public RxJavaObservableProcessV2 (List<String> command) {
processBuilder = new ProcessBuilder(command);
}
public void startAsync () throws Exception {
new Thread(() -> {
try {
process = processBuilder.start();
readInputStream(process);
readErrorStream(process);
process.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
public Observable<String> getInputs () {
return processInputs;
}
private void readInputStream (Process process) {
new Thread(() -> {
BufferedReader br = new BufferedReader( new InputStreamReader(process.getInputStream()));
String line = null ;
try {
while ((line = br.readLine()) != null ) {
this .processInputs.onNext(line);
}
this .processInputs.onComplete();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
private void readErrorStream (Process process) {
new Thread(() -> {
BufferedReader br = new BufferedReader( new InputStreamReader(process.getErrorStream()));
String line = null ;
try {
ArrayList<String> buffer = new ArrayList<String>();
while ((line = br.readLine()) != null ) {
buffer.add(line);
}
if (buffer.size() > 0 ) {
this .processInputs.onError( new Throwable(Arrays.toString(buffer.toArray())));
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
public static void main (String[] args) throws Exception {
RxJavaObservableProcessV2 process = new RxJavaObservableProcessV2(List.of( "tasklist" ));
process.startAsync();
process.getInputs().subscribe(
(input) -> System.out.println( "Input: " + input),
(error) -> System.out.println( "Error: " + error),
() -> System.out.println( "Completed" )
);
}
}
请注意,完整的实现也应注意取消订阅。 订阅返回一个Disposable,应一次性处理完。
说明:
代码看起来很相似,但有一点改动。 现在,所有使用者都被单个ReplaySubject processInputs取代。 这为将程序解耦并以封闭的方式处理操作( 关注点分离 )提供了许多机会。 我在这里使用的ReplaySubject是发出事件的观察者的一种。 这些事件可以作为
- 一个简单的消息,虽然onNext
- 错误,例如通过onError抛出
- 完整状态,尽管onComplete
观察者完成操作后,将无法发出下一个消息或错误消息。 错误也一样。 在RxJava中,所有主题都充当Observer和Observable 。
这很方便。 创建并启动startAsync上的过程后 。 我可以通过订阅getInputs()的Observable返回值来传递该对象,并仍然访问输入和错误流。
这是返回可观察值的转换,这样我们就不会将Subject暴露给外界。 与Observer不同,Observable仅允许用户观察源(对象),但不允许发出事件。
这与前面的示例不同。 以前,一旦消费者消费了一条消息,它就消失了。 如果其他服务需要处理流程中的数据,则需要在外部使用者内显式调用这些服务。 使用ReplaySubject ,只要未调用onError / onComplete ,订阅可观察到的processInputs的每个服务都将接收所有消息。 通过允许可观察对象传递和处理不同服务上的消息,可以改善事件管理。
RxJava是一项很酷的技术,并具有许多优点。 虽然我仅谈到了Observable和ReplaySubject的一般用法,但是您可以访问RxJava或ReactiveX网站来了解更多信息。
我使用了这段代码的变体来管理PS2PDF网站上的进程。 Ps2pdf.com允许用户压缩pdf并转换 jpeg等图像 。 所有这些转换都会产生执行FFMPEG或其他底层开源程序进行实际转换的进程。 我要使用此方法的一个地方是要向最终用户更新视频转换的完成百分比。
我产生了一个FFMPEG进程,并将该Observable进程传递给名为WebSocketService的服务。 它管理用户与系统之间的实时通信。 此WebSocketService订阅输入流Observable并等待数据。 在FFMPEG的情况下,行的输入流采用以下形式。
frame= 1185 fps=337 q=38.0 size= 2048kB time=00:00:20.94 bitrate= 801.1kbits/s speed=5.95x
WebSocketService解码此消息并将进度发送到前端,该进度条将显示在进度栏中,以便用户知道发生了什么。
注意:此代码是用Java 14和RxJava 3编写的。它可以与Java 8+和任何具有当前导入功能的RxJava版本一起使用。
翻译自: https://hackernoon.com/introduction-to-rxjava-observable-pattern-ym493yn4
rxjava 观察者模式