我的应用程序订阅按顺序到达的Observable<Timestamped<byte[]>>
个数据包,并将它们组装成更大的帧。它必须检查每个数据包以找到“帧起始”标头并进行一些小的处理以将数据包组装成有效帧。
如何创建一个新的Observable<Frame>
,将这些已完成的帧发送到Subscriber
?
更新:建议的答案不想为我工作。一些细节:
Observable
会发出Timestamped<byte[]>
个数据包。 Observable
个DataFrame
个对象,每个对象包括来自多个数据包的数据以及其他一些字段。 FrameAssembler
的方法为DataFrame receivePacket( Timestamped<byte[]> packet )
。它返回null
,直到它组装了一个框架,然后它返回并为下一个框架做好准备。 我无法创建输出Observable。我正在尝试这个
Observable<DataFrame> source = Observable
.just( new Timestamped<byte[]>(100, new byte[10]) ) // sample packet
.scan( new FrameAssembler(), (acc, packet) -> acc.receivePacket( packet ))
.filter( frame -> frame != null )
但是lambda带有下划线,消息“lambda表达式中的返回类型错误:DataFrame无法转换为TestScan.FrameAssembler”。
我完全被这个难过了。什么是acc
,它在那做什么?为什么要将DataFrame
返回的receivePacket
转换为FrameAssembler
?为什么new FrameAssembler()
被用作scan()
的第一个参数?
答案 0 :(得分:1)
您可能希望使用双参数scan
运算符:
class ByteAccumulator {
private byte[] buffer = ...
public byte[] receivePacket(byte[] receivedPacket) {
// add the received packet to the buffer
if(containsFullFrame(buffer)) {
return extractFrameAndTrimBuffer();
} else {
return null;
}
}
}
Observable<byte[]> source = ...
source.scan(new ByteAccumulator(), ByteAccumulator::receivePacket)
.filter(frame -> frame != null)
...
编辑:您需要一个中级课来调整FrameAssembler
与scan
期望的内容:
public FrameScanner {
private final FrameAssembler assembler;
private final DataFrame frame;
public FrameScanner() {this(new FrameAssembler(), null);}
public FrameScanner(FrameAssembler assembler,DataFrame frame) {
this.frame=frame; this.assembler=assembler;
}
public getFrame() {return frame;}
public FrameScanner scan(Timestamped<byte[]> nextBytes) {
return new FrameScanner(assembler, assembler.receivePacker(nextBytes));
}
}
现在你应该能够像这样使用它:
.scan(new FrameScanner(), FrameScanner::scan)
.map(FrameScanner::getFrame)
.filter(Objects::nonNull)
嗯......现在我想起来了,而不是abofethis也可能有用:
FrameAssembler assembler=new FrameAssembler();
...
.scan((DataFrame)null, (ignore, packet) -> assembler.receivePacket( packet))
.filter(Objects::nonNull)
答案 1 :(得分:0)
我无法使用scan()
运算符来提供解决方案。我认为问题是在收到完整的数据包集之前返回null
。可观察的运算符链似乎不喜欢空值。
我是如何解决的:
在数据包Observable subscription的onNext()
处理程序中:
Thread.currentThread().setPriority( DATA_RX_PRIORITY );
packetArrayList = DataOps.addPacket( packetArrayList, dataPacket );
if( packetArrayList != null ) { // we have a new complete packet buffer
DataOps.DataFrame frameReturned = DataOps.pBuf2dFrame( packetArrayList );
frameRelayer.onNext( frameReturned ); // send the new frame to the BehaviorSubject
}
addPacket()
例程将每个收到的数据包添加到ArrayList
,但返回null
除非累积完整的帧数据包,否则返回填充ArrayList
。
当收到非空ArrayList
时,pBuf2dFrame()
方法会解析数据包并将它们组装成一个新的DataFrame
对象。
然后是将Observable数据包转换为Observable of DataFrames的技巧:frameRelayer
是BehaviorSubject
(一个RxJava对象,可以作为Observable和Subscriber)。您所要做的就是使用新onNext()
调用其DataFrame
方法,将其传递给frameRelayer
的任何订阅者。