尝试为BufferUntil
实现Observable
(即缓冲元素,并在满足某些条件时发出缓冲列表)
为RxNET实施
定义:
public static IObservable<IList<TSource>> BufferUntil<TSource>(
this IObservable<TSource> source,
Func<TSource, bool> predicate)
{
var published = source.Publish().RefCount();
return published.Buffer(() => published.Where(predicate));
}
使用:
var list = new List<char> { 'a', 'b', 'c', 'd', 'e', 'c' };
list
.ToObservable()
.BufferUntil(c => c == 'c')
.Subscribe(c => c.ToList().ForEach(Console.WriteLine));
结果:
工作正常。发出2 IList
char
['a','b','c']
['d','e','c']
和public <T extends Object> Observable<List<T>> bufferUntil(
Observable<T> source,
final Func1<T, Boolean> bufferClosingCriteria) {
final Observable<T> published = source.publish().refCount();
return published.buffer(new Func0<Observable<T>>() {
@Override
public Observable<T> call() {
return published.filter(bufferClosingCriteria);
}
});
}
尝试为RxJava实现完全相同的
定义:
Character[] arr = {'a','b','c','d','e','c'};
bufferUntil(rx.Observable.from(arr), new Func1<Character, Boolean>() {
@Override
public Boolean call(Character character) {
return character == 'c';
}
}).subscribe(new Action1<List<Character>>() {
@Override
public void call(List<Character> o) {
for (int i = 0; i < o.size(); ++i)
Log.d("LL", o.get(i).toString());
}
});
使用:
SELECT
renewaldate,
DATEDIFF(renewaldate, CURDATE()) AS DaysUntilRenewalDate,
orders.*, customers.*
FROM
orders
JOIN customers ON orders.CustomerNumber = customers.CustomerNumber
WHERE
RenewalDate < DATE_ADD(CURDATE(), INTERVAL 23 DAY)
AND RenewalDate > DATE_SUB(CURDATE(), INTERVAL 4 DAY)
AND IF MakeCall IS NOT NULL THEN WHERE ITS = TO TODAY?
ORDER BY
RenewalDate
结果:
它会发出 3空列表
RxJava实现有什么问题和/或如何解决?
答案 0 :(得分:2)
问题在于,由于默认情况下是同步的,RxJava的工作方式不同,而Rx.NET具有异步源。
RxJava中发生的情况是,当边界订阅refCount时,上游开始立即发出所有字符,遍历字符数组,边界在看到&#34; c&#34;时保持信号。此时,缓冲区操作员甚至没有订阅相同的refCount源,也从未看到任何来自它的数据。
在Rx.NET中,据我所知,List.ToObservable进入另一个线程来发出数组项,这为原始线程提供了足够的时间让缓冲区及其边界得到订阅RefCount。
如果您添加了一个小延迟source.delay(500, TimeUnit.MILLISECONDS).publish().refCount()
,您会看到数据和列表通过,但列表内容仍然不同:
[a, b]
[c, d, e]
[c]
原因是在RxJava中,边界Observable首先被订阅,然后是缓冲订阅者,因此当&#34; c&#34;它来到,它首先到达边界,触发缓冲区分裂,然后缓冲区运算符获得值&#34; c&#34;并将其存储在新缓冲区中。
要确保操作员使用同步源,您必须使用publish(Func1)
而不是refCount:
public static <T extends Object> Observable<List<T>> bufferUntil(
Observable<T> source,
final Func1<T, Boolean> bufferClosingCriteria) {
return source.publish(o -> o.buffer(() -> o.filter(bufferClosingCriteria)));
}
此publish()
变体确保了每个潜在的消费者&#34; o&#34;在消耗源之前设置。
重新订阅订阅以确保&#34; c&#34;最终在缓冲区的末尾有一点涉及:
return source.publish(o -> {
PublishSubject<Object> ps = PublishSubject.create();
return o.buffer(() -> ps)
.mergeWith(Observable.defer(() -> {
o.filter(bufferClosingCriteria).subscribe(ps);
return Observable.empty();
}))
.filter(list -> !list.isEmpty());
});
收率:
[a, b, c]
[d, e, c]