In RxJava2, here is my code:
public void myMethod() {
Flowable.create(e->{
// do sth.
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.computation())
.observeOn(Schedulers.io())
.subscribe(new Subscriber<ContentsWithChannelVO>() {
#Override
public void onSubscribe(Subscription subscription) { // do sth. }
#Override
public void onNext(ContentsWithChannelVO contentAndChannel) { // do sth. }
#Override
public void onError(Throwable throwable) { // do sth. }
#Override
public void onComplete() { // do sth. }
});
doSomething();
}
Here is a synchronized problem.
I want to know how to let my method wait for the flowable onComplete, that is to say doSomething() will be called after the flowable onCompleted.
I have searched for it but it doesn't help.
You can use concat operator, but you need to wrap your method in another observable.
Concat waits to subscribe to each additional Observable that you pass
to it until the previous Observable completes.
You'd have to block the consumption of the flow for that (which is generally not recommended):
public void myMethod() {
Flowable.create(e -> {
// do sth.
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.computation(), false)
.blockingSubscribe(new Subscriber<ContentsWithChannelVO>() {
#Override
public void onSubscribe(Subscription subscription) { // do sth. }
#Override
public void onNext(ContentsWithChannelVO contentAndChannel) { // do sth. }
#Override
public void onError(Throwable throwable) { // do sth. }
#Override
public void onComplete() { // do sth. }
});
doSomething();
}
In this case, having observeOn is pointless. Note also you have to use subscribeOn() with false otherwise the flow livelocks.
If you don't want to execute doSomething if the source fails, use blockingForEach:
public void myMethod() {
Flowable.create(e -> {
// do sth.
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.computation(), false)
.blockingForEach(contentAndChannel -> { /* do sth. */ });
doSomething();
}
Related
I'm creating a list of Observable using a list of values, foreach value a custom Observable. I run them all using merge, but I can't detect which one triggers onNext() or onError()
Like in the code below:
List<Observable<MyHttpRsObj>> observables = new ArrayList<>();
for (String param : paramsList) {
Observable<MyHttpRsObj> objObservable = MyRestClient.get().doHttpRequest(param);
observables.add(fileUploadObservable);
}
Observable<BaseRs> combinedObservables = Observable.merge(observables);
combinedObservables.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<MyHttpRsObj>() {
#Override
public void onCompleted() {
//called only once when all Observables finished
}
#Override
public void onError(Throwable throwable) {
//how to know which Observable has error (which param)
}
#Override
public void onNext(MyHttpRsObj myHttpRsObj) {
//how to know which Observable has sccess (which param)
}
});
It is impossible to know which obsevable triggered the error since you merge all observables into single one.
your best bet is to use one observer for each observable. And a last one for merged Observable.
Like this:
List<Observable<MyHttpRsObj>> observables = new ArrayList<>();
for (String param : paramsList) {
//change to connectable Observable
ConnectableObservable<MyHttpRsObj> objObservable = MyRestClient.get()
.doHttpRequest(param)
.publish();
//don't forget to connect
observable.connect();
observables.add(fileUploadObservable);
//subscribe for each observable
objObservable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<MyHttpRsObj>() {
#Override
public void onCompleted() {
//just partial completed
}
#Override
public void onError(Throwable throwable) {
//you can access param from here
}
#Override
public void onNext(MyHttpRsObj myHttpRsObj) {
//access onNext here
//you can access param from here
}
});
}
Observable<BaseRs> combinedObservables = Observable.merge(observables);
combinedObservables.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<MyHttpRsObj>() {
#Override
public void onCompleted() {
//called only once when all Observables finished
}
#Override
public void onError(Throwable throwable) {
//don't handle error here
}
#Override
public void onNext(MyHttpRsObj myHttpRsObj) {
}
});
PS: use ConnectableObservable to avoid emitting twice
I have this code to wrap a callback in Rx Java 1 and it compiles fine , but now that I have switched to RX Java 2 it does not compile...what is the equivalent in Rx Java 2?
return Observable.fromEmitter(new Action1<AsyncEmitter<Integer>>() {
#Override
public void call(AsyncEmitter<Integer> emitter) {
transObs.setTransferListener(new TransferListener() {
#Override
public void onStateChanged(int id, TransferState state) {
if (state == TransferState.COMPLETED)
emitter.onCompleted();
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
}
#Override
public void onError(int id, Exception ex) {
emitter.onError(ex);
}
});
emitter.setCancellation(new AsyncEmitter.Cancellable() {
#Override
public void cancel() throws Exception {
transObs.cleanTransferListener();
}
});
}
}, AsyncEmitter.BackpressureMode.BUFFER);
UPDATE:
I came up with this, but Do you have to deal with backpressure since its an oncreate call?
return Observable.create(new ObservableOnSubscribe<List<DigitsUser>>() {
#Override
public void subscribe(final ObservableEmitter<List<DigitsUser>> emitter) throws Exception {
mDigitFriends.findFriends((gotEm, users) -> {
emitter.onNext(users);
});
emitter.setCancellable(() -> {
emitter.onNext(null);
});
}
});
If you're worried about backpressure you should use the Flowable class. Here's a quote from the RxJava2 Wiki:
Practically, the 1.x fromEmitter (formerly fromAsync) has been renamed
to Flowable.create.
Here is your example using the Flowable class:
return Flowable.create(new FlowableEmitter<List<DigitsUser>>() {
#Override
public void subscribe(final FlowableEmitter<List<DigitsUser>> emitter) throws Exception {
mDigitFriends.findFriends((gotEm, users) -> {
emitter.onNext(users);
});
emitter.setCancellable(() -> {
emitter.onNext(null);
});
}
}, BackpressureStrategy.BUFFER);
I have the following class, I want to return Subscription object or something else so I can cancel the request from where I have referenced subscribe() method , but subscribe(observer) returns void!
How can I do that?
public abstract class MainPresenter<T> {
protected <T> Disposable subscribe(Observable<T> observable, Observer<T> observer) {
observable.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
}
[New Update]
I used this way temporary, I am waiting for better solutions:
protected <T> DisposableMaybeObserver subscribe(final Maybe<T> observable,
final Observer<T> observer) {
return observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableMaybeObserver<T>() {
#Override
public void onSuccess(T t) {
observer.onNext(t);
}
#Override
public void onError(Throwable e) {
observer.onError(e);
}
#Override
public void onComplete() {
observer.onComplete();
}
});
}
[New Update 2]
[![Screenshot][https://i.stack.imgur.com/mioth.jpg]]
[New Update 3]
[]1
You should maybe use use subscribeWith :
private Disposable mDisposable;
public abstract class MainPresenter<T> {
protected Disposable subscribe(Observable<T> observable, DisposableObserver<T> observer) {
mDisposable = observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(observer);
return mDisposable;
}
Then when you need :
if (mDisposable != null && !mDisposable.isDisposed()) {
mDisposable.dispose();
}
Hope this helps.
I have an Observable<MoviesResponse>. My MovieResponse class contains a getResults() methods returning a List<Result>. This Result class has a getTitle() methods returning a String. I want to call the getTitle() methods of all my Result objects to get all the titles of my movies.
I achieved this with the code below using a foreach loop but I think there is a better way to do this by chaining RxJava operators, I just can't figure it out...
Subscription :
Observable<MoviesResponse> moviesResponseObservable = apiService.getTopRatedMoviesObservable(API_KEY);
subscription = moviesResponseObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<MoviesResponse>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(MoviesResponse moviesResponse) {
List<Result> results = moviesResponse.getResults();
for (Result r:results) {
Log.d(LOG_TAG,r.getTitle());
}
}
});
Interface :
public interface ApiService {
#GET("movie/top_rated")
Observable<MoviesResponse> getTopRatedMoviesObservable(#Query("api_key") String apiKey);
}
You can use a flatmap to transform your observable into an Observable<Result> and then use map to turn that into Observable<String>, which you can then subscribe to.
moviesReponseObservable
.subscribeOn(Schedulers.io())
.flatMapIterable(new Function<MoviesResponse, Iterable<Result>>() {
#Override
public Iterable<Result> apply(#NonNull MoviesResponse moviesResponse) throws Exception {
return moviesResponse.getResults();
}
})
.map(new Function<Result, String>() {
#Override
public String apply(#NonNull Result result) throws Exception {
return result.getTitle();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
#Override
public void onNext(String s) {
Log.d("TAG", s);
}
/* ... */
});
I got the following error with #zsmb13 answer :
new Function : map (rx.functions.Func1) in
Observable cannot be applied to (anonymous
java.util.function.Function)reason:
no instance(s) of type variable(s) R exist so that Function conforms to Func1
Anyway this answer was very helpul I just replaced Function with Func1 and used call method.
subscription = moviesResponseObservable
.subscribeOn(Schedulers.io())
.flatMapIterable(new Func1<MoviesResponse, Iterable<Result>>() {
#Override
public Iterable<Result> call(MoviesResponse moviesResponse) {
return moviesResponse.getResults();
}
})
.map(new Func1<Result, String>() {
#Override
public String call(Result result) {
return result.getTitle();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
Log.d(LOG_TAG, s);
}
});
I have a problem with this async call:
public class myClass {
protected final int idObj;
public void myMethod() {
myService.getObj( new AsyncCallback<List<Object>>() {
#Override
public void onFailure(Throwable caught) {
}
#Override
public void onSuccess(List<Object> listObject) {
idObj = listObject.get(0).getIdObj();
}
});
if(idObj == 1) {
//do something
}
}
}
The value idObj is equal zero at the first time and this if block isn't execute.
How to avoid this?
It's an asynchronous call, that means that the code executed in your onSuccess method will be executed later.
So the if statement is executed but at this time your value still 0.
You should put your if statement in the onSuccess method.