Rxjava onNext not firing via retrofit observable - android

I have this simple retrofit2 api interface which contains
interface Api {
#GET(BuildConfig.END_POINT) Observable<Response> fetchData();
}
So everything is fine when I'm doing a fresh request
but let say I fire a request and I un-subscribe immediately and then I try to fire new request it returns nothing.
So, in code it looks something like this:
in Activity::onPause I perform un-subscription and in Activity::onResume I fire the request again.
My request looks something like this::
api.fetchData()
.timeout(30,TimeUnit.SECONDS)
.doOnNext(new Action1<Response>() {
#Override public void call(Response response) {
list = response.getDataForList();
}
}).flatMap(new Func1<Response, Observable<List<Object>>>() {
#Override public Observable<Object>> call(Response response) {
return Observable.just(list);
}
});
When I tried debugging it, the call is made but doOnNext() is not called. None of the lifecycle methods are called.
And just for clarification from here I'm just returning the observable which I'm using it somewhere else where I'm observing on main thread and subscribing on IO.

Don't use doOnNext, just map. And try to get use to use lambdas, make your code much readable.
api.fetchData()
.timeout(30,TimeUnit.SECONDS)
.map(response -> response.getDataForList())
.flatMap(list -> Observable.just(list));
Now as concept, every time that some observer subscribe to this observable consume the items, then observable automatically unsubscribe the observer. So you don't have to worry about unsubscribe anything.
You can see some practical examples here. https://github.com/politrons/reactive

Related

How to wait first request finish before start second with Rx?

I have an async method makeRequest() with callback. It called many times from different classes of my application. I need that this calls start one by one and never simultaneously.
I want to implement this using Rx. Like this:
public void execute() { // This method called many times from another classes
Observable.just(true)
// what I need to add here?
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(o -> {
internalExecute();
return o;
})
.subscribe();
}
private void internalExecute() { // This method should called only when previous call was finished
makeRequest(this::onRequestFinished);
}
private void onRequestFinished() {
// here is I handle request finish
}
But at now all requests works at parallel. What I need to add here to run requests one by one?
According to comments, you have here separated streams and requests. each client that execute request expect a result from the request. but no requests allowed to run in parallel, in this case I think the easiest way is to limit the Scheduler to an application global background sequential thread Executor, i.e:
Schedulers.from(Executors.newSingleThreadExecutor())
provide somewhere in your app this single thread Executor, in singleton manner of course, it's important that each request stream will use the same object:
private final Scheduler singleThreadScheduler = Schedulers.from(Executors.newSingleThreadExecutor());
public void execute() { // This method called many times from another classes
Observable.just(true)
.map(o -> {
internalExecute();
return o;
})
.subscribeOn(singleThreadScheduler)
.subscribe();
}
private void internalExecute() { // This method should called only when previous call was finished
makeRequest(this::onRequestFinished);
}
private void onRequestFinished() {
//NOTE: you should make sure that the callback execute where you need it (main thread?)
// here is I handle request finish
}
besides that, you're not exposing Observable outside, to the clients, but rather using callback mechanism, you can leverage reactive approach further, by making execute() returning Observable. (and enjoy composition of Obesrvables, operators, proper use of observeOn/subscribeOn, error handling with onError, disposing/unsubscribing etc.), as you're using async api, you can use fromEmitter()/create() (in newer RxJava1 version)), read more here:
private final Scheduler singleThreadScheduler = Schedulers.from(Executors.newSingleThreadExecutor());
public Observable<Result> execute() { // This method called many times from another classes
return Observable.fromEmitter(new Action1<Emitter<? extends Object>>() {
#Override
public void call(Emitter<?> emitter) {
emitter.setCancellation(() -> {
//cancel request on unsubscribing
});
makeRequest(result -> {
emitter.onNext(result);
});
}
})
.subscribeOn(singleThreadScheduler)
}

RxJava pattern for returning cold results, doing more work, then returning hot results

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)

subscribing to an observable when another observable completes

Keeping it simple and short, how to subscribe to an observable in another subscriber's onNext() method so that we can only make nested subscription when the current observable completes its execution. Both the subscriptions will be made on separate threads and the requirement is that the first thread must complete its execution before the second thread is started.
makeObservable()
.subscribeOn(Schedulers.newThread())
.subscribe(new Subscriber<User> {
#override
void onNext(User user){
//do something
//make another subscription here
});
Don't make a new subscription, return another Observable and subscribe to it.
apiCall()
.subscribeOn(<scheduler>)
.observeOn(<scheduler>)
.flatMap(new Func1<User, Observable<Something>() {
#Override
public Observable<Something> call(User user) {
return Observable.just(<example>);
}
});
edit: when the api call returns, flatMap will intercept the stream, and from there, either return an Observable or call a function that returns an Observable (ie another api call).
If they're both emitting the same items, use Observable.concat(), which subscribes to observable N+1 after observable N completes. But it might be worth it to describe your use case in more detail.
Edit: You should be able to do something like:
userClient
.saveUser(user)
.flatMap(userSaveResult ->
userClient
.saveUserDetails(userSaveResult.id, seuser.getDetails))
.onError(...)

RXJava - onBackpressureBuffer + multiple observers not working

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...

RxJava -Do subscribers only run once

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.

Categories

Resources