What I want
I wanted to call a
1 webservice that uploads photo to the server and returns the uploaded link.
2 webservice to save the returned link by 1st webservice.
I wanted to combine two observables and get results as same time
My doubt
What happens if my 1st webservice gets fired successfully and 2nd has encountered an error (eg: Network error, Server error etc)
How can I detect that ? and only retry the 2nd webservice
What I can't do
I can't retry both webservice if 2nd one fails, because I will end up in sending duplicate files for the 1st webservice.
My code
// Upload file (photos,documents etc ):
#POST("some link")
#FormUrlEncoded
Observable<UploadFile> uploadFile(#FieldMap HashMap<String, Object> fields);
// Save link (photos,documents etc ):
#POST("some link")
#FormUrlEncoded
Observable<SaveLink> saveLink(#FieldMap HashMap<String, Object> fields);
// Upload file
Observable<UploadFile> observable = retrofitService.uploadFile(map);
subscriptionUploadFile = observable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<UploadFile>() {
#Override
public void onCompleted() {
CommonFunction.printDebug(TAG, "completed");
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(UploadFile model) {
}
});
// Save link
Observable<SaveLink> observable = retrofitService.saveLink(map);
subscriptionSaveLink = observable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<SaveLink>() {
#Override
public void onCompleted() {
CommonFunction.printDebug(TAG, "completed");
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(SaveLink model) {
}
});
Dependent continuation is typically done via flatMap where you can apply retry to the second Observable:
uploadFile(map)
.subscribeOn(Schedulers.io())
.flatMap(file -> {
map.put("URL", file.getURL());
return saveLink(map).retry(10);
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
Related
I want to implement a logic using RxJava in my android application, which requires three parallel api calls. Only the third api call has a retry logic. If, after having three attempts, the success is achieved then a subsequent call will be made for the fourth api, else only the result of first and second api calls will be passed on to the subscriber.
I tried to achieve this using Zip operator but then got stuck with retry logic for third api call.
Observable<String> observable1 = Observable.just("A","B");
Observable<Integer> observable2 = Observable.just(1,2);
Observable<Boolean> observable3 = Observable.just(Boolean.TRUE, Boolean.FALSE);
Observable.zip(observable1, observable2, observable3, new Function3() {
#Override
public Object apply(String s, Integer integer, Boolean aBoolean) throws Exception {
if (aBoolean==null){
alphabets3.retry(3).doOnComplete(new Action() {
#Override
public void run() throws Exception {
// the result will never be used
}
});
}
return s+integer+aBoolean;
}
}).subscribe(new Observer<Object>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Object o) {
Log.e("onNext-->", o.toString());
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
if any Observable failed in the Zip operator, Zip will fail the stream, the only way I know to achieve parallel execution and error handling with Zip, is to add onErrorResumeNext to each Observable, that map the error to a new model to deal with later .. and handling what you want to do in the zip mapping function ... for example
Obsevable.zip(
observable1.onErrorResumeNext{Observable.just(Model(it)},
observable2.onErrorResumeNext{Observable.just(Model(it)},
observable3.retryWhen {t is TimeOutException} //here you can add your retry logic
.onErrorResumeNext(t -> Observable.just(Model(t)),(m1 , m2, m3) -> Result())
I am new to android and I have a scenario where I want to get get data from multiple api. Let suppose api_a, api_b, api_c, api_d. These api are independent of each other but I want to show data from these api in a mix Recycler View (horizontal and vertical). So I want to make these api call in such a manner so that I can get every api data at a time so that i can display in recycler view.
I already using retrofit 2 but for that I had to chain them one by one which is very lengthy and I think this is not a feasible approach. I know little bit about RX JAVA ,but I only know how to make one request at a time. Please help
There are at least 2 ways to achieve this -
1) Using RxJava Zip operator (for parallel requests)
Get all the observables
Observable<ResponseType1> observable1 = retrofit.getApi_a();
Observable<ResponseType2> observable2 = retrofit.getApi_b();
Observable<ResponseType3> observable3 = retrofit.getApi_c();
Zip the observables to get a final observable
Observable<List<String>> result =
Observable.zip(observable1.subscribeOn(Schedulers.io()), observable2.subscribeOn(Schedulers
.io()), observable3.subscribeOn(Schedulers.io()), new Function3<ResponseType1, ResponseType2, ResponseType3, List<String>>() {
#Override
public List<String> apply(ResponseType1 type1, ResponseType2 type2, ResponseType3 type3) {
List<String> list = new ArrayList();
list.add(type1.data);
list.add(type2.data);
list.add(type3.data);
return list;
}
});
now subscribe on the resultant observable
result.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new Observer<List<String>>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(List<String> s) {
Log.d(TAG, "s is the list with all the data");
}
#Override
public void onError(Throwable e) {
Log.e(TAG, e.getMessage());
}
#Override
public void onComplete() {
}
});
2) Using RxJava flatMap() operator. (To request serially one after another)
This is simple chaining of requests
List<String> result = new ArrayList<>();
Disposable disposable = retrofit.getApi_a()
.subscribeOn(Schedulers.io())
.flatMap((Function<ResponseType1, ObservableSource<ResponseType2>>) response1 -> {
result.add(response1.data);
return retrofit.getApi_b();
})
.flatMap((Function<ResponseType2, ObservableSource<ResponseType3>>) response2 -> {
result.add(response2.data);
return retrofit.getApi_c();
})
.map(response3 -> {
result.add(response3.data);
return response3;
})
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<Response3>() {
#Override
public void onNext(Response3 response3) {
Log.d(TAG, "result variable will have all the data");
}
#Override
public void onError(Throwable e) {
Log.e(TAG, e.getMessage());
}
#Override
public void onComplete() {
}
});
For combining multiple Observables you may want to consider the Merge operator.
This would allow you to combine the stream of multiple requests into a single Observable.
Merge will interleave them as they are emitted. If sequence matters, there is also Concat which will emit from each Observable before continuing with the next.
Rx Doc
Merge: http://reactivex.io/documentation/operators/merge.html
Concat: http://reactivex.io/documentation/operators/concat.html
Merge operator combines multiple observable into one
Set up Base URL of API:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(oktHttpClient.build())
.build();
Now setup two observables for the two network requests:
Observable<JsonElement> Observable1 = ApiClient.getApiService().getApi_1();
Observable<JsonElement> Observable2 = ApiClient.getApiService().getApi_2();
Now we use RxJava's mergemethod to combine our two Observables:
Observable.merge(Observable1, Observable2 )
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<JsonElement>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(JsonElement value) {
Log.d("RESPONSE", "onNext:=======" + value);
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
Log.d("RESPONSE", "DONE==========");
}
});
I use RxAndroid library + Retrofit2.
I Have 2 post requests:
Get all category (return List == each String is category id)
Get ProductsByCategory (return List)
I need load all products and save to DB after start App.
When I create MainFragment I get all Categories:
restApiFactory.getProductService().getCategories(new CategoryRequest(initiatorId))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CategoriesHandler());
and Handle response:
#Override
public void onNext(CategoryResponse value) {
List<CategoryItem> categoryItems = value.getCategoryItems();
...
}
And then I need send another request(ProductsByCategory ) but I not understand how do it?
I can send it in foreach:
for (CategoryItem categoryItem : categoryItems) {
Observable<Products> product = ProductsByCategory...
}
or maby there is some Observable merge ....
I do not know. In general, how to do this? two requests to the server. one will return the list of id and the second product on these id.
You can achieve this by using flaMap in rxjava
This is example demonstrate snippet how to implement it
api.serviceA()
.flatMap(new Func1<FooA, Observable<FooB>>() {
#Override
public Observable<FooB> call(FooA fooA) {
// code to save data from service A to db
// call service B
return api.serviceB();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<FooB>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(FooB fooB) {
// code to save data from service B to db
}
});
You can use an Iterable, call api with CategoryItem and then use toList() in order to obtain a list of ProductsByCategory.
I need to get the content type from a specific URL. I know that we can do it by simply coding:
URL url = new URL("https://someurl.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("HEAD"); // Request Method: GET/POST/UPDATE...
connection.connect();
String contentType = connection.getContentType();
Since this blocks the UI thread (a synchronous operation), how to make a HTTP request using RxJava 2 on Android?
Notes:
I don't want to make this using the AsyncTask. Why?
This is related to RxJava 2 and not version 1.
Give me a clear, simple and concise example if you can.
Use RxJava just operator to leave main thread and continue the process on thread from computation scheduler and then use flatMap to make http call and find content type, network calls should run on threads from IO scheduler and finally observe on main thread and subscribe to result.
Observable.just(1).subscribeOn(Schedulers.computation())
.flatMap(dummyValueOne -> {
return Observable.just(getContentType).subscribeOn(Schedulers.io());
}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<String>() {
#Override
public void accept(String contentType) throws Exception {
//do nextsteps with contentType, you can even update UI here as it runs on main thread
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
Log.e("GetContentType", "exception getting contentType", throwable);
}
}));
You can use a Callable. Here's an example,
Observable.fromCallable((Callable<Object>) () -> {
// do stuff
return object;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Object>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
// so that this can be properly disposed in onDestroy()
compositeDisposable.add(d);
}
#Override
public void onNext(#NonNull Object object) {
// do stuff with the result
}
#Override
public void onError(#NonNull Throwable e) {
}
#Override
public void onComplete() {
}
});
I'd like to see an Android java example of how to sequence a chain of async (= nonblocking) RESTful Volley requests.
Is this what RxAndroid is used for?
If so, I'd like to see the example using RxAndroid.
If not, I'd still like to see a good example w/out diving into CALLBACK HELL!
I tried to do so but ended up in CBHell:
Need to send multiple Volley Requests - in a sequence
I want my result from my 1st request to be used in the 2nd request. Then the result from the 2nd request I want used in the 3rd request. Please, how do I chain such Volley requests?
You could use Rx to chain multiple requests by using the flatMap method.
flatMap requires you to return another Observable of the type of your chosing thus allowing you do something async with another type.
All of the examples below are made with the new rx v2. But all methods and mechanics also apply to v1
Example:
final MyVolleyApi api = new MyVolleyApi();
api.getName()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Function<String, ObservableSource<Integer>>() {
#Override
public ObservableSource<Integer> apply(String name) throws Exception {
return api.getAgeForName(name);
}
})
.flatMap(new Function<Integer, ObservableSource<Date>>() {
#Override
public ObservableSource<Date> apply(Integer age) throws Exception {
return api.getYearOfBirthForAge(age);
}
})
.doOnError(new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
// handle the exception that occurred during one of the api calls
}
})
.subscribe(new Consumer<Date>() {
#Override
public void accept(Date date) throws Exception {
// do something with the 3rd argument here
}
});
This is the MyVolleyApi dummy class:
public class MyVolleyApi {
public Observable<String> getName() {
return Observable.just("Rx");
}
public Observable<Integer> getAgeForName(String name) {
return Observable.just(24);
}
public Observable<Date> getYearOfBirthForAge(int age) {
return Observable.just(new Date());
}
}
This could apply to anything, it's not volely specific at all