Observable onNext() not called for Observable.zip() - java

I have multiple requests (upload files) into Observable and I want to execute them in parallel. The code is:
private void myMethod(List<String> filePathsList) {
List<Observable<String>> observables = new ArrayList<>();
for (String filePath : filePathsList) {
MultipartBody.Part multipartFile = getMultipartFile("some_file_name", filePath);
//here I'm just creating request from Retrofit restclient - the problem can't be here ;)
Observable<String> fileUploadObservable = UploadsRestClient.get().sendFile(multipartFile, "another_post_param");
observables.add(fileUploadObservable);
}
Observable<String> combinedObservable = Observable.zip(observables, new FuncN<String>() {
#Override
public String call(Object... args) {
return null;
}
});
combinedObservable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<String>() {
#Override
public void onCompleted() {
//called at the end
}
#Override
public void onError(Throwable throwable) {
//called if error occurs
}
#Override
public void onNext(String string) {
//should be called foreach request, but it's called only after the last one
}
});
}
The problem is that onNext() is called only after the last call is done, before onCompleted(),how can I get triggered after each request?

Related

D/OkHttp: <-- HTTP FAILED: android.os.NetworkOnMainThreadException Retrofit2 +RxJava2

I'm trying to learn how Retrofit+RxJava work and I'm testing some example. If I call a List of objects I can print on console this list of objects. Here below the code:
Disposable disposable = apiInterface.getArea("4744", ".")
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribeWith(new DisposableObserver<List<Area>>() {
#Override
public void onNext(List<Area> areas) {
Log.d("Response"," Value Area "+areas);
}
#Override
public void onError(Throwable e) {
Log.d("Error","JSON Error "+ e.getMessage());
}
#Override
public void onComplete() {
}
}
);
Model class:
public class Area {
#SerializedName("v_area")
private String typeArea;
#SerializedName("area")
private String desArea;
public Area(String typeArea, String desArea) {
this.typeArea = typeArea;
this.desArea = desArea;
}
public String getTypeArea() {
return typeArea;
}
public void setTypeArea(String typeArea) {
this.typeArea = typeArea;
}
public String getDesArea() {
return desArea;
}
public void setDesArea(String desArea) {
this.desArea = desArea;
}
}
Whereas if I try to receive a list of objects and convert in a list of strings with RxJava operators I get the error:"D/OkHttp: <-- HTTP FAILED: android.os.NetworkOnMainThreadException"
Disposable disposable = apiInterface.getArea("4744",".")
.map(response -> Observable.fromIterable(response))
.flatMap(x->x)
.map(Area::getTypeArea)
.toList()
.toObservable()
.subscribe(this::handlerResponse,this::handlerError);
}
private void handlerResponse(List<String> strings) {
System.out.println(strings);
}
private void handlerError(Throwable throwable) {
Log.d("Error ","Response Error "+throwable.getMessage());
}
Can anyone help me to solve?
One more question please...Can I have an example to catch response error? Because I no receive any http status error, but only a null on console.

RxJava not displaying the data

I am new in RXjava. I have impliment it in my project but it is not getting the data and didnot display it. what is the problem here?
My viewModel
public LiveData<Resource<List<Item>>> makeApiCallTopArticles() {
final MutableLiveData<Resource<List<Item>>> mediumObjectsList = new MutableLiveData<>();
mediumObjectsList.setValue(Resource.loading());
APIService apiService = RetroInstant.getRetroMediumClient().create(APIService.class);
Observable<CnnResponse> observable = apiService.getNewsObjectsList("http://rss.cnn.com/rss/cnn_topstories.rss",
"", "25");
Observer<CnnResponse> observer = new Observer<CnnResponse>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(CnnResponse value) {
List<Item> articles = new ArrayList<>();
assert value != null;
List<Item> responce = value.getItems();
for (int i = 0; i < Objects.requireNonNull(responce).size(); i ++) {
if (!Objects.equals(Objects.requireNonNull(responce.get(i).getEnclosure()).getLink(), null) && !Objects.equals(responce.get(i).getTitle(), "")) {
articles.add(responce.get(i));
}
}
mediumObjectsList.postValue(Resource.success(articles));
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
};
observable.subscribe(observer);
return mediumObjectsList;
}
ViewModel before I added RXjava
public LiveData<Resource<List<Item>>> makeApiCallTopArticles() {
final MutableLiveData<Resource<List<Item>>> mediumObjectsList = new MutableLiveData<>();
mediumObjectsList.setValue(Resource.loading());
APIService apiService = RetroInstant.getRetroMediumClient().create(APIService.class);
Call<CnnResponse> call = apiService.getNewsObjectsList("http://rss.cnn.com/rss/cnn_topstories.rss",
"", "25");
call.enqueue(new Callback<CnnResponse>() {
#Override
public void onResponse(#NotNull Call<CnnResponse> call, #NotNull Response<CnnResponse> response) {
List<Item> articles = new ArrayList<>();
assert response.body() != null;
List<Item> responce = response.body().getItems();
for (int i = 0; i < Objects.requireNonNull(responce).size(); i ++) {
if (!Objects.equals(Objects.requireNonNull(responce.get(i).getEnclosure()).getLink(), null) && !Objects.equals(responce.get(i).getTitle(), "")) {
articles.add(responce.get(i));
}
}
mediumObjectsList.postValue(Resource.success(articles));
}
#Override
public void onFailure(#NotNull Call<CnnResponse> call, #NotNull Throwable t) {
mediumObjectsList.setValue(Resource.error(t.getMessage() != null ? t.getMessage() : "Unknown Error"));
}
});
return mediumObjectsList;
}
.......................................................................................................................................................................................
Try to add logs to: onNext and onError method. Just to understand that you really receive a response or maybe you have some errors during the request. If you receive an error that can be a reason.
When you're using Rx you should use schedulers to avoid perform long term operation on the main thread. replace you subscription with:
observable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(observer);
Try this,
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);

How to properly await the completion of multiple async calls from a swagger client in java?

I need to make multiple asynchronous calls through a Swagger generated client, and await the completion of all of the request before continuing. Ideally, I want the request to be made in parallel with each other. My background is in C#, and I think I am looking for the Java equivalent of Task.WhenAll.
Here is the Swagger code I am calling:
public com.squareup.okhttp.Call getPersonAsync(Integer personid, final ApiCallback<PersonResponse> callback) throws ApiException {
ProgressResponseBody.ProgressListener progressListener = null;
ProgressRequestBody.ProgressRequestListener progressRequestListener = null;
if (callback != null) {
progressListener = new ProgressResponseBody.ProgressListener() {
#Override
public void update(long bytesRead, long contentLength, boolean done) {
callback.onDownloadProgress(bytesRead, contentLength, done);
}
};
progressRequestListener = new ProgressRequestBody.ProgressRequestListener() {
#Override
public void onRequestProgress(long bytesWritten, long contentLength, boolean done) {
callback.onUploadProgress(bytesWritten, contentLength, done);
}
};
}
com.squareup.okhttp.Call call = getPersonValidateBeforeCall(personid, progressListener, progressRequestListener);
Type localVarReturnType = new TypeToken<PersonResponse>(){}.getType();
apiClient.executeAsync(call, localVarReturnType, callback);
return call;
}
In my code, I have a list of personIds, and I need to make a request for each one to get the PersonResponse and add it to a list. The personApi is a Swagger class that returns an OkHttp Call object.
Here is the code I have for it right now:
for (int personId: personIds) {
personApi.getPersonAsync(personId, new ApiCallback<PersonResponse>(){
#Override
public void onSuccess(PersonResponseresult, int statusCode, Map<String, List<String>> responseHeaders) {
persons.add(result);
}
#Override
public void onFailure(ApiException e, int statusCode, Map<String, List<String>> responseHeaders) {
System.out.printf("ApiException Message: %s", e.getMessage());
}
#Override
public void onUploadProgress(long bytesWritten, long contentLength, boolean done) {
// TODO Auto-generated method stub
}
#Override
public void onDownloadProgress(long bytesRead, long contentLength, boolean done) {
// TODO Auto-generated method stub
}
});
}
Right now this code continues executing, but I only want to continue executing the rest of the code after each PersonResponse has been added to the list. What is the best way to do that in Java?

Callback Duplicate Code

I'm using okhttp3 with asynchronous callbacks to get JSONArrays/JSONObjects from the server and then parsing them and creating the particular object which is passed to the callback function.
Most of the callback code is the same for every method, but there are some lines of code that differ.
Is there a pattern that I can use to reduce the lines of code so that I don't have to write the same code over and over again for the different objects?
I marked the lines of code that differ for every method.
The problem I have is calling the particular JSON parsing function without using switch/case and varying the callback object.
//-----------------------differs-------------------------
public void getUser(final HTTPResponseCallback<User> callback)
{
//-----------------------differs-------------------------
final String url = domain + USERS;
//-------------------------------------------------------
okHttpClient.newCall(buildRequest(url)).enqueue(new Callback()
{
Handler handler = new Handler(Looper.getMainLooper());
#Override
public void onFailure(Call call, IOException e)
{
handler.post(new Runnable()
{
#Override
public void run()
{
callback.onFailure();
}
});
}
#Override
public void onResponse(Call call, final Response response) throws IOException
{
if (response.isSuccessful())
{
try
{
String responseBody = response.body().string();
//-----------------------differs-------------------------
JSONObject jsonResponse = new JSONObject(responseBody);
final User user = JsonParser.parseUser(jsonResponse
//------------------------------------------------------
handler.post(new Runnable()
{
#Override
public void run()
{
//---------------------------------------last parameter differs----------------------------------------------
callback.onSuccess(new HTTPTransaction(response.code(), response.message(), response.header("ETag")), user);
//-----------------------------------------------------------------------------------------------------------
}
});
}
catch (JSONException e)
{
...
}
}
else
...
}
}
}
1) Make in parameterized with <T> as type can differs:
public class CallBackWrapper<T> {
...
public void getUser(final HTTPResponseCallback<T> callback) { ...
2) Introduce callback object for unique parts which will return instance of type T:
interface Worker {
T run(String responseBody);
}
public <T> void getUser(final HTTPResponseCallback<T> callback, Worker worker) { ...
3) Invoke needed worker:
String responseBody = response.body().string();
//-----------------------differs-------------------------
final T obj = worker.run(responseBody);
//------------------------------------------------------
handler.post(new Runnable()
{
#Override
public void run()
{
//---------------------------------------last parameter differs----------------------------------------------
callback.onSuccess(new HTTPTransaction(response.code(), response.message(), response.header("ETag")), obj);
//-----------------------------------------------------------------------------------------------------------
}
});

How to use Netflix ObservableResult and rxJava within Asynchronous mode

I was trying to use netflix observable however I managed to do so only synchronously:
This is how I define the remote call:
#Named
public class BroConsumerService {
..
#HystrixCommand(fallbackMethod = "stubbedMethod")
public Observable<String> executeObservableBro(String name) {
return new ObservableResult<String>() {
#Override
public String invoke() {
return executeRemoteService(name);
}
};
}
private String stubbedMethod(String name) {
return "return stubbed";
}
//here I am actually invoking (and observing this method)
#RequestMapping("/executeObservableBro")
public String executeObservableBro(#RequestParam(value = "name", required = false) String name) throws ExecutionException, InterruptedException {
Observable<String> result= broConsumerService.executeObservableBro(name);
result.subscribe(new Observer<String>() {
#Override
public void onCompleted() {
System.out.println("completed");
}
#Override
public void onError(Throwable e) {
System.out.printf(e.getMessage());
}
#Override
public void onNext(String s) {
System.out.println("on next..");
}
});
}
But that works synchronously. I want to be able to "listen" to the executeObservableBro before I execute it. and each time it's being executed ill get notified.
Example would be highly appreciated.
Thanks,
ray.
you have to provide schedulers in subscribeOn method like:
public static void main(String[] args) throws InterruptedException {
Observable<Integer> observable2 = Observable.create(subscriber->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Arrays.asList(1, 2, 3).forEach((value)-> subscriber.onNext(value));
subscriber.onCompleted();
subscriber.onError(new RuntimeException("error"));
});
System.out.println("Before");
observable2
.subscribeOn(Schedulers.io()).subscribe(
(next) -> log.info("Next element {}", next),
(error) -> log.error("Got exception", error),
() -> log.info("Finished")//on complete
);
System.out.println("After");
//Thread.sleep(5000); //uncomment this to wait for subscriptions, otherwise main will quit
}
Its not async by default :)

Categories