I have an Observable and subscribe to it. I need to not miss any emitted result, so I use onBackpressureBuffer like following:
Observable<Data> observable = observable.onBackpressureBuffer();
if (BuildConfig.DEBUG)
{
observable
.subscribeOn(HandlerScheduler.from(dataManager.getBackgroundHandler()))
.observeOn(HandlerScheduler.from(dataManager.getBackgroundHandler()))
.subscribe(new MeasuringSubscriber(...));
}
// Here is the real observer that I need in my app
observable
.subscribeOn(HandlerScheduler.from(dataManager.getBackgroundHandler()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Data>()
{
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(Data data) {
}
});
The MeasuringSubscriber is a custom subscriber that just logs how long a task needs, that's all.
Problem
If I add the MeasuringSubscriber, the subscribers do not work anymore and never emit a result. Why? And how can I make that working?
EDIT - NEW PROBLEM
Currently it's working, but the MeasuringSubscriber is somehow blocking, meaning, first all items are emitted one by one to the MeasuringSubscriber and only afterwards all items are emitted one by one to the main subscriber... Any ideas what could cause that?
I have a solution for that - I can extend my main observalbe from the MeasuringObservable - but I rather would like to know why this happens and how to avoid this...
I tried using publish + connect, but still it does emit all items to the first subscriber before emitting them to the second one...
Related
I have a method that returns an Observable<List<Long>>, which are ids of some Items. I'd like to go through this list and download every Item using another method that returns Observable<Item>. currently I'm doing it by below code.
#Override
public Observable<List<Item>> getResponses(List<Long> requests) {
return Observable.from(requests).
flatMap((Func1<Long, Observable<Item>>) restRequest -> getResponseEach(restRequest)).toList();
}
It's working fine, but it returning all the response in on go, I mean when all download get finish then my onNext() get invoked,
Main Question But alternatively I need to emit every response one-by-one(Any Order) once each item fetched successfully from server, so my onNext should be invoked every-time time individually for each item.
How would I do this using RxJava operators?
You have to remove the toList() operator. The toList() will emit only after all the emissions of the upstream have been completed, and it will collect the results and will emit as a Single<List<YourResultObject>>
You can return the observable returned by the flatMap in your code and you will get the results one by one,
public Observable<Item> getResponses(List<Long> requests) {
return Observable.fromIterable(requests)
.flatMap(restRequest -> getResponseEach(restRequest));
}
Now, your getResponses method will return Observable<Item> instead of Observable<List<Item>>
And you can subscribe to this function as follows
getResponses(ids)
.subscribe(new DisposableObserver<Item>() {
#Override
public void onNext(Item item) {
// each item will be received here one by one
}
#Override
public void onError(Throwable e) {
// handle any occured error during the operation
}
#Override
public void onComplete() {
// all operations completed
}
});
This is my first time developing in reactive paradigm world, and i started using rxjava2/rxandroid2, as based on videos I've watched and articles I've read, it seems like its better to start with 2 as 1 has so many changes that differs the library in a big scale, but now I'm having some trouble looking for something that acts like the
unsubscribe()
method of the former rxjava/rxandroid library
my goal is just quite simple
perform an API call(network operation)
listen and react on what the observable will emit (happy path)
do not listen or react when app goes to PAUSE state
or, unsubscribe on observable as soon as android goes to the pause life-cycle
, based on the resources around there is
dispose()
method of rx2, what I understand with this is that it disposes any current resources(in my case, base on what i understand, invoking this will make the observable detach itself to any observer).
but that doesn't seem to be what I'm expecting, please have a look at the ff codes:
public class MainActivity extends AppCompatActivity {
final Disposable disposable = new Disposable() {
#Override
public void dispose() {
Log.e("Disposed", "_ dispose called.");
}
#Override
public boolean isDisposed() {
return true;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Observer<Object> observer = new Observer<Object>() {
#Override
public void onSubscribe(Disposable d) {
Log.e("OnSubscribe", "On Subscribed Called");
}
#Override
public void onNext(Object value) {
Log.e("onNext", "Actual Value (On Next Called).");
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
}
#Override
public void onComplete() {
Log.e("OnComplete", "On Complete Called.");
}
};
EventsApiService.getInstance().testApi().testCall()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnDispose(new Action() {
#Override
public void run() throws Exception {
Log.e("Disposed?", "__ Dispose");
}
})
.subscribe(observer);
observer.onSubscribe(disposable);
}
#Override
public void onPause() {
super.onPause();
disposable.dispose();
}
}
I'm having this output:
03-23 09:08:05.979 3938-3938/edu.rx.study E/Disposed: _ dispose called.
03-23 09:08:13.544 3938-3938/edu.rx.study E/onNext: Actual Value (On Next Called).
03-23 09:08:13.544 3938-3938/edu.rx.study E/OnComplete: On Complete Called.
I was expecting that onNext won't be called anymore or maybe both onNext and onComplete, but that doesn't seem to be working, am i missing something here? or theres something i totally don't understand, my thinking with my code is,
"what if onNext is performing something towards a widget(UI)(Observer) and the app goes on pause state?", I don't want that UI(Observer) to react on that particular UI anymore.
Many people are right, and I admit, switching to reactive programming is quite hard especially rxjava2/rxandroid2 has a very steep learning curve.
Any help will be greatly appreciated.
You're handling incorrectly the Observer and the Disposable, the Disposable object should be handing to you by the Observable, you can't just create it by yourself, and call explicitly Observer.onSubscribe() with it, as it's not connected to the Observable and does not terminates it.
(you can also notice that Observer.onSubscribe is called twice, one by the Observable and one by you)
What you should do, is simply use the onSubscribe(Disposable d) method at your Observer to save the Disposable, which will be called automatically by the Observable and will hand you the correct Disposable object, that you can successfully terminate the network operation with it.
Another option is, to not use at all the subscribe(Observer o) method, but other overloads that takes your onNext/onError/onCompleted as parameters, and returns Disposable object, which you can dispose (unsusbcribe) with it, for terminating the network call.
I'm learning RxJava so please be gentle. I've watched the tutorials, done the reading, searched SO, however, I'm still having some problems transforming my AsyncTaskLoader. For some reason, I can't find a pattern of operators to achieve my task (although I think it's a common one). What I'm trying to do is the following: return an Observable my fragment could subscribe to. The observable should do the following on subscribe:
1) Fetch data from the local database by doing 2 queries, running some logic and returning results;
2) Fetching data from API;
3) Synchronising the new API data with the database;
4) Repeating step one and returning results;
So far I've transformed my db calls and my API calls to return observables. I'm trying to understand how I can emit the cold results and continue with the chain. I could probably keep the two operations separately, and use the same subscriber to subscribe to both? But I'm not sure how that would work if my new loader-replacement class returns an observable... Also I don't really need to process the results from the second observable - I just need for the first one to replay when the second one finished.
So far I have the following:
public Observable<StuffFetchResult> getColdStuff() {
return Observable.zip(mDataSource.listStuff(), mDataSource.listOtherStuff(),
(stuff, moreStuff) -> {
List<Stuff> mergedList = new ArrayList<>();
// do some merging stuff
return new StuffFetchResult(mergedList);
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
Assume I also have getHotStuff() that will do the API call and the synchronisation with the database, if that's the right approach, and return the same Observable. However, I'm stuck on the next step - how can I restart the first observable to replay once hotStuff has completed, without adding another subscriber?
EDIT:
I've made some progress and I think all I need now is to join it all up. I have my two methods:
1) getColdStuff() is pretty much as described above
2) getHotStuff() will do call to the API, synchronise with the database, and return an Observable. The idea was to call getColdStuff() again after getHotStuff() has finished in order to refresh the UI, so actual result returned from getHotStuff() can be ignored. All it needs to do is to trigger getColdStuff() once done.
I've tried the suggestion in the answer to and created the following:
BehaviorRelay<Observable<StuffFetchResult>> callSequence = BehaviorRelay.create();
Observable<StuffFetchResult> valueSequence = Observable.switchOnNextDelayError(callSequence.toSerialized());
valueSequence.subscribe(new Subscriber<StuffFetchResult>() {
#Override
public void onCompleted() {}
#Override
public void onError(Throwable e) {}
#Override
public void onNext(StuffFetchResult result) {
// UI stuff
}
});
callSequence.call(loader.getColdStuff());
I can subscribe to valueSequence here and use callSequence.call(loader.getColdStuff());, which will run the first method and produce results in onNext() of my subscription, which I can use for my UI. However, I'm not sure how to run getHotStuff() in parallel and also do a different action on it when it returns. Also getHotStuff() returns a different type of Observable so I can't really use the same callSequence?
EDIT 2
Using two subscribers, I can achieve the required behaviour I think. Not really sure if that's the right way to go about it though.
loader.getHotStuff()
.subscribeOn(Schedulers.io())
.subscribe( new Subscriber<Object>() {
#Override
public void onCompleted() {}
#Override
public void onError(Throwable e) {}
#Override
public void onNext(Object stuffWeDontCareAbout) {
callSequence.call(loader.getColdStuff());
}
});
if i understand your scenario correctly, you may want something like that -
BehaviorSubject<Observable<T> callSequence = BehaviorSubject.create();
Observable<T> valueSequence = Observable.swithOnNextDelayError(callSequence.toSerialized());
your subscriber will be listening to the valueSequence, and whenever you need to "restart", you will call this -
callSequence.onNext(call.cache()); // *call* is Observable<T>
(i leave the .subscribeOn/.observeOn configuration to you)
I'm trying to make a simple "button debouncer" which will count filtered clicks and display it thru a TextView. I want to filter rapid/spam clicks in a way that clicks with less than 300ms time-gap in-between are ignored.
I did my research and stumbled upon Rx's awesome debounce() which in theory should do the exact thing I wanted..
..or so I thought. As the app seemed to only register the first click; the counter won't increment no matter how long I tried to wait.
Here's a piece of my code:
...
RxView.clicks(mButton)
.debounce(300, TimeUnit.MILLISECONDS)
.subscribe(new Subscriber<Object>() {
public int mCount;
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(Object o) {
mText.setText(String.valueOf(++mCount));
}
});
...
What am I doing wrong? I've tried to run the thing without debounce() and it worked flawlessly (the counter will increment everytime the button got clicked).
Thanks in advance!
Note the following in the documentation on the debounce operator:
This variant operates by default on the computation Scheduler (...)
Or, code-wise, this currently happens:
public final Observable<T> debounce(long timeout, TimeUnit unit) {
return debounce(timeout, unit, Schedulers.computation());
}
As a result, the subscriber's callbacks are invoked on that same computation scheduler, since nothing is explicitly instructing otherwise.
Now, attempting to update a view (that's what's happening in onNext()) from any other thread than the main/ui thread, is a mistake and it will lead to undetermined results.
Fortunately, the remainder of the quote above provides the solution too:
(...) but you can optionally pass in a Scheduler of your choosing as a third parameter.
This would lead to:
RxView.clicks(mButton)
.debounce(300, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
.subscribe(...);
Alternatively, you can still let the debounce happen on the computation scheduler, but receive the notifications on the main/ui thread:
RxView.clicks(mButton)
.debounce(300, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
Either way will ensure that the notifications are received on the main/ui thread and thus that the view is updated from the correct thread.
I have some confusion on subscribers and when they react to observers. Lets say i have the following simple observer with a subscriber that does an action:
Observable.just(preferences.getBoolean(C"vibrate", false))
.subscribeOn(Schedulers.io())//observe on new thread
.observeOn(AndroidSchedulers.mainThread()) //subscribe(listen) on main thread
.subscribe(new Action1<Boolean>() {
#Override
public void call(Boolean shouldVibrate) {
if (shouldVibrate)
Toast.makeText(context,"i should vibrate now",Toast.SHORT).show();
}
});
I realize the observer gets called right away when this code is first seen. But what if the shared preference is changed again afterwards, will this code run again automatically or does it only run everytime i call subscribe ? What if i wanted it to run everytime the shared preference was altered (sort of like a watcher).
It really depends on the observable. I would suggest reading "Hot" and "Cold" Observables on the reactive Observable docs.
In your case, this is a Cold observable. It will resubscribe each time it is subscribed to. However, you only subscribe to it once. Your code snippet will actually block on the preferences fetch (probably not a huge problem), but it will only emit one preference.
I would suggest using the ContentObservable class in the RxAndroid extension lib for RxJava, which you are already using (because of AndroidSchedulers).
It would look something like this (This is back-of-napkin code, I have not compiled or ran this):
// Defer the observable so it gets a fresh preference value. Also, we'll
// be using it a few times.
final Observable<Boolean> vibratePreference = Observable.defer(
new Func0<Observable<Boolean>>() {
#Override
public Observable<Boolean> call() {
return Observable.just(preferences.getBoolean("vibrate", false));
}
});
vibratePreference
.concatWith(ContentObservable.fromSharedPreferencesChanges(preferences)
// Only consider changes to the vibrate preference.
.filter(new Func1<String, Boolean>() {
#Override
public Boolean call(final String key) {
return "vibrate".equals(key);
}
})
// Each time the preference changes, get the latest value.
.flatMap(new Func1<String, Observable<Boolean>>() {
#Override
public Observable<Boolean>(final String unusedKey) {
return vibratePreference;
}
}))
.scheduleOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe( /* ...and so on. */ );
Also, if you are doing this on an activity or a fragment, I would strongly suggest looking into bindActivity and bindFragment in AppObservable in RxAndroid to make sure you are binding this observable to the lifecycle. You also may want to store a CompositeSubscription that you can empty in onPause and restore subscriptions in onResume. Those are slightly off-topic but will most likely be useful very soon.