Android app freezes after upgrading rxandroid 0.24 -> 0.25
zella opened this issue · comments
I used io.reactivex:rxandroid:0.24.0
and io.reactivex:rxjava-string:0.22.0
After ugrade dependency to io.reactivex:rxandroid:0.25.0
, app became freezes on
public static String joinedBy(List<String> src, String separator) {
return StringObservable.join(Observable.from(src), separator).toBlocking().single();
}
rxjava-string:1.0.0 is same.
And this problem issue in normal java environment too.
My test logic
Observable<String> columns = Observable.from("a,b,c,d".split(","))
.map(i -> String.format("%s.%s", "prefix", i));
Observable<String> query = StringObservable.join(columns, ",");
System.out.println(query.toBlocking().single());
io.reactivex:rxjava:1.0.8 + io.reactivex:rxjava-string:* , is working.
io.reactivex:rxjava:1.0.9~ + io.reactivex:rxjava-string:* is not working.
So I guess some blocking logic changed in rxjava 1.0.12.
I found some specific two check points.
point 1. in BlockingObservable#blockForSingle
...
private T blockForSingle(final Observable<? extends T> observable) {
final AtomicReference<T> returnItem = new AtomicReference<T>();
final AtomicReference<Throwable> returnException = new AtomicReference<Throwable>();
final CountDownLatch latch = new CountDownLatch(1);
Subscription subscription = observable.subscribe(new Subscriber<T>() {
@Override
public void onCompleted() {
latch.countDown(); // Runtime doesn't reach this line. So CountDownLatch continue on 1 state.
}
@Override
public void onError(final Throwable e) {
returnException.set(e);
latch.countDown();
}
@Override
public void onNext(final T item) {
returnItem.set(item);
}
});
try {
latch.await(); // So deadlock situation.
} catch (InterruptedException e) {
subscription.unsubscribe();
Thread.currentThread().interrupt();
throw new RuntimeException("Interrupted while waiting for subscription to complete.", e);
}
...
point 2. StringObservable#join
public static Observable<String> join(final Observable<String> source, final CharSequence separator) {
return source.lift(new Operator<String, String>() {
@Override
public Subscriber<String> call(final Subscriber<? super String> o) {
return new Subscriber<String>(o) {
boolean mayAddSeparator;
StringBuilder b = new StringBuilder();
@Override
public void onCompleted() {
String str = b.toString();
b = null;
if (!o.isUnsubscribed())
o.onNext(str);
if (!o.isUnsubscribed()) // This code is true after unsubscribed. So problem in point 1 issue.
o.onCompleted();
}
I don't understand why. I describe just situation.
@davidmoten the bug is in join not requesting max but just the amount the child does. Simplest fix is to add an onStart.
I think a fix has been merged in #24. I'll attempt to get it released.