I am trying to use RxJava in combination with Retrofit in my Android app.
I came to a point where I need to retrieve (GET) a url from some model class, and if its not available, POST to another endpoint to generate it, then retrieve it with GET again.
The idea is that the end result is always a url (provided there was not an error, of course), so if its not there, we create it and then retrieve it.
I can do this with RxJava by just nesting calls, but this does not seem to "reactive", so I thought maybe the and-when-then sounds like what im looking for? I tried looking for examples but these three words are quite difficult to search due to them being so common.
Is it possible to combine observables to achieve what I describe?
Let's assume you have the following methods:
apiManager.makeGETRequest(); //returns Url or throws an Exception
apiManager.makePOSTRequest(); //returns Url
Use handy onErrorResumeNext operator:
apiManager.makeGETRequest()
.onErrorResumeNext(t -> apiManager.makePOSTRequest())
...
It intercepts an Exception and replaces it with Observable. In your case if makeGETRequest() succeeds, than downstream will ignore onErrorResumeNext, otherwise apiManager.makePOSTRequest() will be called.
P.S. Don't forget to check what kind of exception you receive in onErrorResumeNext.
I hope this can be useful for you.
https://github.com/darylteo/rxjava-promises/tree/master/rxjava-promises
If you need code sample for retrofit + rx usage you can follow this link.
http://randomdotnext.com/retrofit-rxjava/
Related
I am relatively new to reactive world , In My codebase I have decided to apply reactive philosophy in a very incremental way which is taking small step at a time . whit this motivation I have a changed a function this way
public List<Task> getFilteredTask() {
return Observable.fromIterable(TaskDataSource.getAllTasks())
.filter(task -> !task.isCompleted && !task.getPriority>=1)
.sorted((task!, task2) -> task.title.compareTo(task2.tilte)).toList().blockingFirst();
I Had to useBlockingX() operator my client recieves List for this time being . So I had to unwrap the Single Observable .
But I am getting exception after calling this ? Please Help me What am I doing wrong here ?
Please post your Log messages , although I am pretty much sure You are getting this error as you possibly calling this method from MainThread . As You know long running operation supposed to be deferred off to Main Thread .
Second Thing I would Like to address is RxJava was created with Laziness in mind . Here you are violating it with Observable Creation with Observable.fromIterable(TaskDataSource.getAllTasks()) as You can see TaskDataSource.getAllTasks() is getting called even before there is any observer subscribed to it . So I think with this modification you will get rid of the crash
public Observable<Task> getFilteredTask() {
return Observable.defer(() ->
Observable.fromIterable(TaskDataSource.getAllTasks())).subscribeOn(Schedulers.io())
.filter(task -> !task.isCompleted && !task.getPriority>=1)
.sorted((task!, task2) -> task.title.compareTo(task2.tilte))
.observeOn(AndroidSchedulers.mainThread());
}
Further more I would like to say modify you'r calling client for accepting Observable instead of List . Because Using BlockinX() is strongly discouraged by Rx Community because Instead of Being data Pushed as It is ready you are pulling data and blocking the thread
Hope it will help
in the app I am currently working on I use retrofit to create an Observable <ArrayList<Party>>.
Party has a hostId field as well as a field of type User which is null at the point of creation by Retrofits GsonConverter. I now want to use hostId to make a second request getting the user from id and adding the User to the initial Party. I have been looking into flatmap but I haven't found an example in which the first observable's results are not only kept but also modified.
Currently, to get all parties without the User I am doing :
Observable<ArrayList<Party>> partiesObs = model.getParties();
partiesObs.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::handlePartyResponse, this::handleError);
How would I go about adding User to every Party without having to call model.getUsers() in the onSuccess() method of the inital call and then having to iterate through the two lists?
I understand that flatmap() returns a new Observable while map doesn't but I am unsure about how to use either in this scenario.
Thank you
As in the comment, you should try and get the backend API changed for something like this to avoid an inelegant and inefficient solution.
If this is not feasible, you could probably do something like this:
.flatMapIterable(list -> list)
.flatMap(party -> model.getUser(party.hostId),
(party, user) -> new Party(user, party.hostId, party.dontCare))
Where:
flatMapIterable flattens the Observable<ArrayList<Party>> into an Observable<Party>
The overload of flatMap takes a Function for transforming emissions (Party objects) into an ObservableSource (of User objects) as the first parameter. The second parameter is a BiFunction for combining the Party and User objects which you can use to create a fully fledged Party object.
The last step is much easier if you have a copy or clone operation on the Party object that takes a previous instance and adds fields to it.
I need to implement synchronous calls with RxJava and Retrofit.I have an ArrayList of ids. I need to iterate this array and make the call to the web server for each id using Retrofit but I know how to do this only async, could U tell me how to do this like in queue when after one call finished the next one starts.
Your question is worded quite ambiguous, but I think I might have understood it. Starting from a list of items you can create an observable of these with from(). This values can be mapped afterwards your API calls. Using concatMap() guarantees the order of your results, so you effectively get an observable over your results. Which these you can do whatever you want, even call toBlocking() on it and make the observable synchronous. But there should not be any need for this.
List<Result> results =
Observable.from(ids)
.concatMap(id -> callToWebServer(id))
.toList()
.toBlocking()
.single();
This code will execute them synchronious
Observable.from(ids)
.map(id -> callToWebServer(id).toBlocking().first())
But you need to handle all network errors from callToWebServer() carefully in map().
I use Retrofit to interact with a REST API and RxJava do manipulate the data I receive.
In the code snippet below I make an API call and use the map operator to save the data I receive before moving on with other operations against the stream.
retrofitApi.registerDevice(mDevice)
.map(new Func1<Device, Device>() {
#Override
public Device call(Device device) {
// The only purpose of the map() operator
// is to save the received device.
magicBox.saveDeviceId(device.getId());
return device;
}
})
.otherOperations()...
My question is: is there a better operator for the job? I feel like I misuse the map operator.
Following Egor's answer I did some research and, based on Dan Lew's blogpost and this question, the correct answer appears to be
doOnNext.
Looks like doOnEach() is what you're looking for, however haven't tried it myself.
I have some requests I'm making with Android Volley. As the Listeners are doing things like turning the response JSON into objects, I'd like to test them to make sure they're doing the right thing. Thing is, I'm not very caught up on how to do unit testing. I do have Robolectric with JUnit set up, but any help would be appreciated. How would I go about setting up my test so I can test the Listener object passed into the request?
It's enough to look at CacheDispatcher:
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
This is where the request's response is created, using abstract parseNetworkResponse method (in case that you have implemented it), and then:
mDelivery.postResponse(request, response);
which actually fires the listeners, if you dig into the code. Rest of the stuff is thread related. I'd reccomend implementing simple testing routine that takes static NetworkResponse, and calls mDelivery's postResponse.
This actually also means, that you could possibly not go this way - it is enough to test which method (Response.success or Response.error) was called - this is your first unit test. Secondly, just test your listeners.