Does Retrofit support rx.Future/Task/Async/Single? - android

I've found nice example of usage RxJava at this article:
Subscription subscription = Single.create(new Single.OnSubscribe() {
#Override
public void call(SingleSubscriber singleSubscriber) {
String value = longRunningOperation();
singleSubscriber.onSuccess(value);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1() {
#Override
public void call(String value) {
// onSuccess
Snackbar.make(rootView, value, Snackbar.LENGTH_LONG).show();
}
}, new Action1() {
#Override
public void call(Throwable throwable) {
// handle onError
}
});
But since I am using Retrofit I would like to create RetrofitService and use Single class to combine the result of two requests to backend into one dataset, as described:
When subscribing to a Single, there is only an onSuccess Action and an
onError action. The Single class has a different set of operators than
Observable, with several operators that allow for a mechanism of
converting a Single to an Observable. For example, using the
Single.mergeWith() operator, two or more Singles of the same type can
be merged together to create an Observable, emitting the results of
each Single to one Observable.
Is it possible to achieve this (and how)?

Yes, see Retrofit Adapters
Only worked with Retrofit2.0

Related

Best way to get List from Observable in Rxjava

I'm just exploring Rxjava in one of my android application, and got stuck at one place, honestly speaking I'm very new to this library so don't mind if my question frustrate someone;-)
So I'm trying to access the Room Database using RxJava where I'm returning the Observable List, once I get this Observable I'm trying to use map operator to get a list of ids & query again the database, which again returns me the Observable List but the map operator expects List as a return type. How can I tackle this please suggest?
Below is the code snippet:
private void getAllPcbs() {
isLoading.setValue(true);
getCompositeDisposable().add(
getRepositoryManager().loadAllPcbDetails()
.flatMap((Function<List<PcbDetails>, ObservableSource<?>>) pcbDetails -> {
List<Long> pcbList = new ArrayList<>();
for (PcbDetails details : pcbDetails)
pcbList.add(details.getPcbId());
return getRepositoryManager().loadAllPcbs(pcbList);
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onSuccess, this::onError)
);
}
private void onError(Throwable throwable) {
isLoading.setValue(false);
}
private void onSuccess(Object o) {
isLoading.setValue(false);
pcbList.setValue((List<Pcb>) o);
}
public interface DbHelper {
Observable<List<PcbDetails>> loadAllPcbDetails();
Observable<List<Pcb>> loadAllPcbs(List<Long> pcbIdList);
}
Go like
getRepositoryManager().loadAllPcbDetails()
.flatMapIterable {
listPcbDetail-> listPcbDetail
// listPcbDetail is ArrayList<PcbDetails>
// Converts your list of ids into an Observable
// which emits every item in the list
}
.flatMap { pcbDetail ->
// pcbDetail is PcbDetails
getRepositoryManager().loadAllPcbs(pcbDetail.pcbIdList)
}.subscribe { listPcb ->
// listPcb is ArrayList<Pcb>
}

How to test rxjava chaining?

Hi i have created implementation that uses flatmap to chain two requests together with the final outcome being a response object returned from the second request and wondering if it is possible to mock these two chained response objects?
Here is the main code
delegator.requestOne(requestData)
.flatMap ({ response ->
if(response.isSuccessful){
cookieStorage.saveSessionCookies(response.header(cookieStorage.COOKIE_HEADER_NAME)!!)
}
delegator.requestTwo
})
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(object : SingleObserver<ResponseTwo>() {
#Override
fun onSubscribe(Disposable d) {
}
#Override
fun onSuccess(responseTwo :ResponseTwo) {
callback.onSuccess(responseTwo)
}
#Override
public void onError(Throwable e) {
}
});
If this did not have a flatmap and handled just one request/response i would write the below using mockito
Mockito.when(network.makeReq()).thenReturn(Single.just(responseOne));
But how can i do something like this:
Mockito.when(foodHygieneController.getLocalAuthorities()).thenReturn(Single.just(requestOne)).thenReturn(requestTwo)??
assuming requestOne and RequestTwo are hard coded mock values of my choosing
You simply mock every request (call to a mocked object) that is part of your Rx chain.
In your case:
Mockito.when(delegator.requestOne(...)).thenReturn(...)
Mockito.when(delegator.requestTwo(...)).thenReturn(...) / Mockito.when(delegator.requestTwo(responseOne)).thenReturn(...)
You can then test that the 'output' (emitted items) from that chain are what you expect them to be, for example with a TestSubscriber, or in your example, that callback is called with the ResponseTwo you expect / have mocked.
The Rx chain will operate in your test exactly as it does when running the code 'normally'.
What you cannot do is mock the behaviour of the Rx chain, e.g. you cannot mock how flatMap{} operates.

RxJava2 how call in parallel different request

I'm Really new on this but What I'm trying to do is
Do two call on parallel both are objects, then I need create a new object using the properties of both
This is a pseudo example that I need
OperatorINeed(service.callOne(), service.callTwo())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.concatMap(new BiFunction<ObjectA, ObjectB, ObjectC>() {
public ObjectC apply(ObjectA objectA, ObjectB objectB) {
// do things
return objectC;
}
})
onErrorResumeNext(...)
but I can't find any concrete example of this thing
use zip() operator, it will collect both emissions from the two service Observables that will run in parraell, and there you provide the BiFunction to map both Objects properties to a new single Object, afterwards you can apply concatMap() with objectC :
Observable.zip(service.callOne(), service.callTwo(),
new BiFunction<ObjectA, ObjectB, ObjectC>() {
#Override
public ObjectC apply(ObjectA objectA, ObjectB objectB) throws Exception {
// do things
return objectC;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.concatMap(objectC -> { //create an Observable using objectC})
.onErrorResumeNext(...)

In what occasion can onNext() be called more than once?

I have defined and interface, with an endpoint that returns JSON. Retrofit converts this JSON into MyObject. It could be also a list, map, etc, it doesn't matter now.
This is how I subscribe.
subscription = Retrofit.create(MyApi.class)
.doSomething()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<MyObject>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(MyObject myObject) {
}
});
My question is:
Is it possible that onNext is called more than once?
If yes, in which occasion?
In your case, no it's impossible, of course if you do not emit more items in doSomething() method.
But there is another, quite usual cases, for instance, if you use Local first approach and subscribing on hot observable which will emit new item each time when data in data base has change.
E.g. using retrofit:
#Override
public Observable<List<FollowMeUser>> getFollowMeUsers() {
return realm.where(FollowMeUser.class)
.findAll()
.asObservable()
.filter(RealmResults::isLoaded);
}
getFollowMeUsers()
.subscribe(users -> {Timber.d("saved data has changed")}, Timber::e);
Each time when you will insert/modify/delete FollowMeUser collection, all subscribers of getFollowMeUsers will be notified.
If your retrofit returns an array/list of data, onNext is called multiple times.
But if your retrofit returns a single data objext, onNext will be called only once.
Example:
//POJO
class User {
int userId;
String UserName;
}
//POJO
class UserData {
List<User> users;
}
interface RetrofitGithub {
#GET("...")
Observable<List<User>> getUsers();
#GET("...")
Observable<UserData> getUserData();
}
If you subscribe to getUsers() onNext will be called multiple N times.(N = size of the list)
If you subscribe to getUserData() onNext will be called only once.

RxAndroid: Is there a clean way to get a Subscriber object from an Observable?

So from my view model I call my Observable in another class:
getAuthentication.kickoff()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<RxOkHttpResponse>() {
#Override
public final void onCompleted( ) {
getAlbums();
}
#Override
public final void onError(Throwable e) {
userMsgHandler.showToast(mParent,mParent.getString(R.string.error_cannot_authenticate));
}
#Override
public final void onNext(RxOkHttpResponse response) {
mSubscription = response.subscription;
}
});
So this call obviously returns an Observable. So I'm wondering what the cleanest way to call subscriber.unsubscribe() on this Observable that is returned or if there even is a way (Right now I return it in onNext -- but I'm not happy bout that)
So is there a way to format the code to store .subscribe() in a member variable:
.observeOn(AndroidSchedulers.mainThread())
mSubscriber = .subscribe(new Subscriber<RxOkHttpResponse>() {
...
I'm using v 1.1.0
The answer depends on whether you're using RxJava 1 or 2. In case of RxJava 1 subscribe() will return Subscription instance which you can then call unsubscribe() on. However for RxJava 2 I believe you need to add onSubscribe()
This is the syntax I was looking for:
mSubscriber = ( getAuthentication.kickoff()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
).subscribe(new Subscriber<RxOkHttpResponse>() {
...
Now I can easily store mSubscriber in my view model for clean up triggered by OnDestroy() in my Activity

Categories

Resources