Retrofit 2 adapter rxjava ошибка

I have this simple service on my server at http://192.168.1.12:8080/api/hooray:

router.route('/hooray/')
    .get(function (req, res) {
        res.status(200).send({ result: true, message: "hooray" })
    })

It does work from Postman, but from my Android application I unable to reach that url, and I don’t know why.

That’s the (simplified) code:

Service’s Interface

public interface HoorayAPI {
    @GET("hooray/")
    Observable<HoorayResponse> hooray();
}

My custom Response class: HoorayResponse

public class HoorayResponse{
    @SerializedName("result")
    @Expose
    private boolean result;

    @SerializedName("message")
    @Expose
    private String message;

    public HoorayResponse(boolean result, String message) {
        this.result = result;
        this.message = message;
    }

    // Getter and setter ...
}

Caller

public void foo(){
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://192.168.1.12:8080/api/")
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    HoorayAPI service = retrofit.create(HoorayAPI.class);

    Observable<HoorayResponse> hoorayObservable = service.hooray();

    hoorayObservable
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<HoorayResponse>() {
                @Override
                public void onCompleted() {}

                @Override
                public void onError(Throwable e) { e.printStackTrace(); }

                @Override
                public void onNext(HoorayResponse response) {
                    System.out.println("Hooray!!!");
                }
            });
}

When I call the foo() method, I get this error:

retrofit2.adapter.rxjava.HttpException: HTTP 404 Not Found 
    at retrofit2.adapter.rxjava.OperatorMapResponseToBodyOrError$1.onNext(OperatorMapResponseToBodyOrError.java:43)
    at retrofit2.adapter.rxjava.OperatorMapResponseToBodyOrError$1.onNext(OperatorMapResponseToBodyOrError.java:38)
    at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$RequestArbiter.request(RxJavaCallAdapterFactory.java:173)
    at rx.internal.operators.OperatorSubscribeOn$1$1$1.request(OperatorSubscribeOn.java:80)
    at rx.Subscriber.setProducer(Subscriber.java:211)
    at rx.internal.operators.OperatorSubscribeOn$1$1.setProducer(OperatorSubscribeOn.java:76)
    at rx.Subscriber.setProducer(Subscriber.java:205)
    at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:152)
    at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:138)
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:50)
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
    at rx.Observable.unsafeSubscribe(Observable.java:8460)
    at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94)
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
    at java.lang.Thread.run(Thread.java:776)

I can’t figure out because the error: HTTP 404 Not Found. That service is reachable and it works. I wrote a service API for login in a very similar way to HoorayAPI, with a POST method, and it works. Why it doesn’t work here? I mean, the code seems to be correct.

when i use rxjava i got this error

error: retrofit2.adapter.rxjava2.HttpException: HTTP 404 Not Found
at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:54)
07-02 23:53:39.876 18974-20433/com.susham.salamtk W/System.err: at retrofit2.adapter.rxjava2.BodyObservable$BodyObserver.onNext(BodyObservable.java:37)
at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:44)
at io.reactivex.Observable.subscribe(Observable.java:12036)
at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:34)
at io.reactivex.Observable.subscribe(Observable.java:12036)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:579)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
07-02 23:53:39.876 18974-20433/com.susham.salamtk W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
07-02 23:53:39.877 18974-20433/com.susham.salamtk W/System.err: at java.lang.Thread.run(Thread.java:818)

this is my configration

without rxjava adapter it works fine i try it both in the same activity to be sure it work

@get(«api/Ambulancetypes»)
fun getAmbulanceTypes(): Observable<List>
//

private val builder = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient.build())
var retrofit = builder.build()

//
apiService.getAmbulanceTypes()
.subscribeOn(Schedulers.io())
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(this::handleResponse, this::handleError)

//

implementation «com.squareup.retrofit2:retrofit:$retrofit_version»

 implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"

ext{
retrofit_version = «2.4.0»
}

Содержание

  1. Dan Stone
  2. Search This Blog
  3. Custom Error Handling with RxJava & Retrofit 2
  4. ServiceCallback
  5. RxJava
  6. MyRxErrorHandlerFunction
  7. Legacy Project Refactoring: Handling API Errors with Retrofit2 and RxJava
  8. How to use Retrofit 2 for handling APIs
  9. Handling API errors in Retrofit: Solutions
  10. Handling API errors in Retrofit: Solution drawbacks
  11. The best way to handle API errors
  12. Conclusion
  13. Responses/Errors with Retrofit 2 & RxJava2
  14. Simple Retrofit Api Call
  15. ViewModels and Subjects
  16. The Trigger
  17. The Api Call
  18. Errors!
  19. Get Down to Business
  20. Let’s handle an error.
  21. Generic Error Handling
  22. Connecting to the View
  23. Conclusion

Dan Stone

Search This Blog

Custom Error Handling with RxJava & Retrofit 2

  • Get link
  • Facebook
  • Twitter
  • Pinterest
  • Email
  • Other Apps

Recently I started redeveloping an Android app in order to try and take advantage of some of the new techniques that «modern Android devs» are using. I must say, the many hours of reading up and research was totally worth it — MVP keeps everything much simpler, Retrofit stops me from having to build API calls myself and RxJava handles threading — letting me focus on the code instead of avoiding the dreaded memory leaks.

Before I added RxJava, in an effort to modularise things, I made use of Retrofit Callbacks. These had some extra logic that would take the erroneous server response and parse it into my own custom Exception . I would check for response error messages and error codes even when the server returned something other than code 2XX and then create a custom ApiError object. I was able to create my own Callback that extended the Retrofit callback, and performed some logic in the Retrofit methods that passed the relevant Exception to two new abstract methods that would either return a custom response object (parsed using GSON) or one of my new Exceptions . I want to try and keep the blocks of code in this article to a minimum, so I’ll just paste in the key code.

ServiceCallback

The ServiceCallback above takes the POJO that Retrofit will convert the JSON to. If the server sends a response, we can handle the data in onResponse() — for example we’ll call the success() method if the HTTP Status code is 200. If this isn’t the case, we’ll call the failure() method passing a new instance of our custom ApiException . ServiceResult and ServiceException are both custom classes.
ServiceResult simply contains the parsed Object and the Okhttp Response object (in case response details are ever needed)

We’ve made our own subclass of Exception that holds the message and cause. This form of Exception is called when there’s an internet or other device related issue. If the server returns an error in its response, a subclass is returned (see below).

Let’s say we make an call with incorrect parameters. The server will respond with an error message, and if it’s a really good API, a custom error code.

Okay. So that’s a lot of code so far — hopefully you’re still with me. Seeing the code for yourself makes it slightly easier to follow I hope.
So now all that is done, we can actually use the ServiceCallback . We’ll use it in place of RetrofitCallback in .enqueue() . We’ll have the two methods — success and failure — we can override these and add our logic to. In the failure callback, we can check which type of ServiceError it is using instanceof and adjust our logic accordingly. We can even get the error message out of ServiceApiException .

As I said earlier, ReactiveX is a popular way of making asynchronous calls, therefore if I’m trying to make my Java API complete, I’ll want to include support for both basic Callbacks and RxJava.
I’ve structured my singleton Service class like this:

The code above simplifies the process of making an API call, and it also mean that you can change the parameters before making the call. Usually Rx Calls don’t send the response data to the onError callback. We need to come up with our own way of intercepting the response. The solution? Create our own ErrorHandlingFunction thats used in .onErrorResumeNext()

MyRxErrorHandlerFunction

This takes a copy of the Observable and checks for all the different kinds of errors that are possible (for example, an HTTP Error). When each one is found it returns a new Observable with the one of our ServiceException ‘s. It looks similar to our custom Callback seen above.

There are other ways of intercepting the error, however the method shown above should not affect any other operations being performed on the Observable . Now we just need to add it to the Service class (since it was ommitted above). Also, in order to reduce further boilerplate code I have set the thread for .subscribeOn() here.

Now we can use the Observable returned from the authenticateRx method like we would for any other Observable .

That’s it. A lot of work for little gain, however, over time it should start to pay off. If the server has a certain error format you can adapt to it, if the response request changes you can change it in one place and be done with it. Etc.
I no longer need to worry about parsing the errors and can just check the error code, which stays constant. Worth it in my opinion. Let me know if you end up taking inspiration through Twitter.

Источник

Legacy Project Refactoring: Handling API Errors with Retrofit2 and RxJava

Legacy projects have their own peculiarities, and working with them can be a challenge. Such projects are constantly expanding, and developers are adding new API requests, technologies, frameworks, libraries, and more. An architecture that was once great becomes outdated and can’t handle so many extra structures. This is when the time comes for refactoring.

I’m an Android developer at Mobindustry who is currently working on a five-year-old project that continues to evolve rapidly. Because it’s rather old, there are lots of APIs we use to make different features work and address the backend. Recently, the app struggled to sustain all these API requests, and I needed to find a solution.

For many developers including myself, Retrofit has become a standard tool for network interactions

I chose RxJava and Retrofit as my main tools to solve this issue. RxJava is a reactive programming framework that makes it easy to model real-world situations and manage asynchronous operations.

Retrofit is a flexible and convenient framework that helps to establish effective and fast API management. It’s a type-safe HTTP client for Android and Java. For many developers including myself, it has become a standard tool for network interactions. It makes sending requests and receiving responses extremely easy.

To receive API responses as objects, you can use converters. With the help of an additional adapter, you can receive not only a Call type of object but also reactive types of objects like these:

  • Observable, Observable , and Observable
  • Flowable, Flowable , and Flowable
  • Single, Single , and Single
  • Maybe, Maybe , and Maybe
  • Completable, for which reactive components are dismissed

T stands for the type of object we get.

In this article, I’ll explore how you can get an out-of-the-box Subscriber or Observer to process the data you get from Retrofit in RxJava. This will allow you to process all errors in one place: the app’s business logic. This means that you can:

  • save the data you receive in a response
  • calculate the next request
  • show the result of the request.

How to use Retrofit 2 for handling APIs

I’ll give you a detailed tutorial on handling APIs with Retrofit.

1. The first step is to add dependencies to your project:

Note that my Retrofit and adapter version is 2.5.0. It’s important that they’re the same.

2. Initialize Retrofit:

3. Describe the interface you’ll use to get the API requests to Retrofit:

4. To perform the same task in RxJava, you’ll need to use this code:

5. The request itself should look like this:

The callback will store the server response in the form of an object, Response . If the response is OK!, you’ll get the expected List in the onResponse(Call call, Response response) method with the help of the response.body() request.

6. Now you need to address Retrofit. It will then send a request to the server and return an RxJava data stream:

7. To handle the Rx response, you’ll need to use this code:

This is what you need to set up the process of handling APIs with Retrofit. What happens, however, if your app receives an error as a response to the request? This is a very important part of API handling. If you don’t provide your app with ways to handle different errors, it can lead to crashes.

Handling API errors in Retrofit: Solutions

There are two types of errors you can receive while working with API requests:

  • HTTP errors
  • Request processing errors

To make sure the app works consistently, you need to handle the way it processes and reacts to errors. There are several ways to do this:

1. Add a custom interface Interceptor to your okHttp
2. When using a Call object, you can use the following lines of code in the method realization callback:

  • For processing errors: void onResponse(Call call, Response response);
  • For HTTP errors: void onFailure(Call call, Throwable t);

3. When using RX, use this:

  • For processing errors: In the method onNext(T t), in case you find the error in the t object
  • For HTTP errors: In the method void onError(Throwable t), when you process the error depending on the type of exception

You can also create an Observable interface (or alternative interfaces such as Single, Maybe, and Completable) for the Subscribe function.

Handling API errors in Retrofit: Solution drawbacks

Each of the solutions I’ve mentioned have their drawbacks; some are bigger, some smaller. You need to take them into account when you handle API errors to choose the best solution for your project and make sure you know what to do if your solution doesn’t work as intended.

For example, implementing the Interceptor interface can seem like a perfect solution at first because you can handle errors at the early stages in OkHttp. However, this is where you can encounter some problems.

Each of the solutions I’ve mentioned have their drawbacks; some are bigger, some smaller. You need to take them into account when you handle API errors

The deal is that to implement error handling behavior in your app, you need to transfer the app’s Context into an OkHttpClient. Error handling behavior includes notifying the user about an error or making an additional or alternative request to the backend.

When you transfer the Context into an OkHttpClient, this can lead to unpredictable errors in the application if you change the Context. This can also result in memory leakage.

Using an RxJava2Adapter to process the errors directly in the Subscribe function is a great idea until there are more than two methods in which you need to process errors.

The best way to handle API errors

While experimenting with different solutions for API error handling, I came up with a perfect solution that involves processing errors in a reactive data flow. I achieved this using RxJava.

The idea is to get the response to our request in the form of an object with or without an error, or to receive an HTTP error as a certain type of exception. This way we can handle internal errors like we handle HTTP errors.

This is what we need to make it work.

1. First, create an object that will contain the Context and the app’s behavior in case of any errors. For this, you’ll need to implement an interface for creating different error processors:

This is how I implemented the processor:

2. At this point, we need to create a class with two methods. These methods will process the server responses and HTTP errors.

These are all the necessary things you need to do to get prepared for API error handling. The last thing to do is to make a request and add the following to subscribe():

  • map() – Used to check if there are any errors in the server response. If there are, this function processes them or generates an exception.
  • doOnError() – A processor that initializes with the onError method in subscribe(). This processor allows us to process the HTTP exceptions or exceptions that were created in catchError(String code, String error) in the ResponseWrapper class.

This is all you need to effectively handle your API errors in the best way possible.

Conclusion

Handling API errors with Retrofit2 and RxJava is a great solution for a few reasons.

First, you get rid of excessive, repeating code. Usually an app reacts to errors in the same way, and the overall behavior to the similar errors has to be identical. For example, if you receive a 404 error, you need to show an error pop-up (e.g. Toast). In case of a 403 Forbidden error, an app should display the authorization screen.

The second reason to use this strategy is its flexibility. If you need another behavior, you can just add it to onError() in the subscribe() function.

The third reason, and the best one, is that you can treat the response like a data stream in reactive programming. Legacy AsyncTasks won’t bother you here.

I hope this article is useful for you. If you have any questions about handling API requests and errors, be sure to contact Mobindustry.

Источник

Responses/Errors with Retrofit 2 & RxJava2

For a while now I haven’t been completely satisfied with how I was handling REST Api errors. It seemed messy and confusing; never knowing completely how to handle the errors in a clean concise way with very few documented solutions.

That is when I stumbled across a code base that contained a nice solution using RxJava. I’m not going to lie, it took me a couple of hours to get my head around what was going on but in the end I came out the other side more comfortable with RxJava so I think it’s well worth trying to understand other peoples code even if it at first it looks overly complex.

RxJava is cool. Kotlin is amazing. Retrofit is fantastic. Github repo with code here. Thanks for coming.

Simple Retrofit Api Call

You may have done this many times with Retrofit; defining an API call that returns an Observable. This may look like so in your API interface class —oh btw, this example is in Kotlin although you can do exactly the same thing in Java just in a more bloated and ugly way.

We have our endpoint which looks great. Now we need to use this endpoint.

ViewModels and Subjects

I, like a lot of people, enjoy clean code and making that code as testable as possible. For this reason I either use the MVVM or MVP pattern. For the purposes of this example and the fact that it’s only very recently come out, I will be using the new ViewModel architecture component provided by Google although I won’t be explaining in depth this component.

The Trigger

Now the scenario is this. I have a button on my view, which when pressed, will makea get request to the API. How do we go about this in a reactive way?

From my ViewModel I expose an Observer which is a PublishSubject like so:

Then from my Activity I call this Subject’s onNext() when I want it triggered like so.

The Api Call

In it’s most basic form, which we will expand later on, here is an Observable that will emit when the refreshSubject’s onNext is called. As you can see, for now we’re limiting it to only the first page of results.

So in the above code I am taking my refreshSubject , passing it’s emission to the movieDbApi.getPopularMovies() observable and making sure only the list of results gets returned rather than the response wrapper.

This Observable is retrieved from the view like so:

Perfect. We are getting responses from the Api with a list of movies being printed each time the button is pressed.

Errors!

With out current configuration we have an issue. If an error occurs, such as with Retrofit throwing an HttpException or there being a SocketTimeoutException due to a poor internet connection, this observable will no longer work! Button presses after the onError is called will not cause the basicApiCall to emit any items because it’s stream as been terminated.

We could return a new Observable every time the view binds to the ViewModel but this would not work for our code later on so let’s get it working this way. To do this we wrap any errors thrown by our Api call in an object.

This is the wrapper object. This can be used so that we can still retrieve our errors but the observable also continues emitting items. We use it like so:

Notice the map on the getPopularMovies observable. This is the best case and if it reaches this point the Api call was successful. However, if an error is thrown, thats when the onErrorResumeNext operator comes into play. This basically says, if a throwable is emitted then return this Observable instead.

But this looks ugly I hear you say

This is Kotlin after all, there must be a way to make it look good! Check this addition to the Result class out. NB- this is outside of the Result class but inside the same file.

This is one of my favourite features in Kotlin; extensions. It allows you to extend classes you wouldn’t normally have control over and allows you to do cool things like this.

Yes we had to add a line to map our emission to a list of movies but the .toResult() is a lot nicer to read than the previous example.

Our View then updates like so to show the results:

Get Down to Business

So our Api call can now be triggered multiple times, even after an error occurs. However, to handle individual error codes there would have to be far too much business logic in the view. Now lets get more involved with RxJava!

So I’m happy with our basic Api call observable that returns a Result
. The problem is I want to share the emission of these items with other observables. To do this we turn our regular Observable into a ConnectableObservable by adding the .publish() parameter onto the end.

This basicApiCall Observable we have been using will no longer be accessible by the user. Instead, we want to give the view access, only to specific Observables that correspond to certain states we expect. Take a successful response for example. We know there will be no exception thrown and a list of MovieSummary objects will be returned. Let’s create an Observable just for this.

Now we can guarantee that when this observable fires, it’s only going to be because it received a successful response from the Api and the view only has to handle this scenario.

Let’s handle an error.

When a page of value 0 is passed to the endpoint, it returns with an HttpException that has a code of 424 . This is a good one to handle as we can guarantee the response each time, however it’s real world applications may not be as useful.

As you can see we are sharing the basicApiCall , ConnectableObservable in the same way the success Observable does. This one however only emits an item if an HttpException with the code 424 is emitted.

But hold on! That’s ugly! Let’s add another few extensions to our Result.kt file, but not in the class, to make our code nicer.

Now our specific page error observable becomes:

And our successful observable becomes:

Generic Error Handling

We have handled the case of catching specific errors now let’s catch all the others!

Connecting to the View

We have already connected the successful observable to our view (which now requires some modification after the extension addition) , now lets hook up the errors.

Notice the bindToLifecycle() method. This is so we don’t leak our disposables using a library called RxLifecycle.

We subscribe to each observable on the io thread so it runs in the background and we observe on the main thread so we can do things to our Ui when items are emitted.

For now these are just logging the different errors and responses but you can see how you can quickly hook this up to different parts of your Ui.

Conclusion

I much prefer this way of handling my Api requests. Everything is separated out with clear and distinct observables for different scenarios. Business logic is also far removed from the view.

Источник

I’m an Android developer at Mobindustry who is currently working on a five-year-old project that continues to evolve rapidly. Because it’s rather old, there are lots of APIs we use to make different features work and address the backend. Recently, the app struggled to sustain all these API requests, and I needed to find a solution.

For many developers including myself, Retrofit has become a standard tool for network interactions

I chose RxJava and Retrofit as my main tools to solve this issue. RxJava is a reactive programming framework that makes it easy to model real-world situations and manage asynchronous operations.

Retrofit is a flexible and convenient framework that helps to establish effective and fast API management. It’s a type-safe HTTP client for Android and Java. For many developers including myself, it has become a standard tool for network interactions. It makes sending requests and receiving responses extremely easy.

To receive API responses as objects, you can use converters. With the help of an additional adapter, you can receive not only a Call type of object but also reactive types of objects like these:

  • Observable, Observable<Response>, and Observable<Result>
  • Flowable, Flowable<Response>, and Flowable<Result>
  • Single, Single<Response>, and Single<Result>
  • Maybe, Maybe<Response>, and Maybe<Result>
  • Completable, for which reactive components are dismissed

T stands for the type of object we get.

In this article, I’ll explore how you can get an out-of-the-box Subscriber or Observer to process the data you get from Retrofit in RxJava. This will allow you to process all errors in one place: the app’s business logic. This means that you can:

  • save the data you receive in a response
  • calculate the next request
  • show the result of the request.

How to use Retrofit 2 for handling APIs

I’ll give you a detailed tutorial on handling APIs with Retrofit.

1. The first step is to add dependencies to your project:

implementation 'com.squareup.retrofit2:retrofit:version’
implementation 'com.squareup.retrofit2:converter-gson:version'
implementation 'com.squareup.retrofit2:adapter-rxjava2:version'

Note that my Retrofit and adapter version is 2.5.0. It’s important that they’re the same.

2. Initialize Retrofit:

public static Client getInstance() {
	return ourInstance;
}
Retrofit retrofit = new Retrofit.Builder()
	.baseUrl(BASE_URL)
	.client(okHttpClient)
	.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
	.build();

3. Describe the interface you’ll use to get the API requests to Retrofit:

 public interface Api {
@GET("users")
Call<List> getUserList();
}

4. To perform the same task in RxJava, you’ll need to use this code:

@GET("users")
Observable<List> getUserList();
}

5. The request itself should look like this:

public void getUsers (ResultCallback callback) {
Call<List> call = Api.getInstance().getUserList();
call.enqueue(callback)
}

The callback will store the server response in the form of an object, Response<List>. If the response is OK!, you’ll get the expected List in the onResponse(Call call, Response response) method with the help of the response.body() request.

6. Now you need to address Retrofit. It will then send a request to the server and return an RxJava data stream:

public Observable<List> getUsers () {
return  Api.getInstance().getUserList();

7. To handle the Rx response, you’ll need to use this code:

getUserList()	
.observeOn(AndroidSchedulers.mainThread())
	.subscribe(users -> 
{//some action},
throwable->
{//error handling}
);

This is what you need to set up the process of handling APIs with Retrofit. What happens, however, if your app receives an error as a response to the request? This is a very important part of API handling. If you don’t provide your app with ways to handle different errors, it can lead to crashes.

Handling API errors in Retrofit: Solutions

There are two types of errors you can receive while working with API requests:

  • HTTP errors
  • Request processing errors

To make sure the app works consistently, you need to handle the way it processes and reacts to errors. There are several ways to do this:

1. Add a custom interface Interceptor to your okHttp
2. When using a Call object, you can use the following lines of code in the method realization callback:

  • For processing errors: void onResponse(Call call, Response response);
  • For HTTP errors: void onFailure(Call call, Throwable t);

3. When using RX, use this:

  • For processing errors: In the method onNext(T t), in case you find the error in the t object
  • For HTTP errors: In the method void onError(Throwable t), when you process the error depending on the type of exception

You can also create an Observable interface (or alternative interfaces such as Single, Maybe, and Completable) for the Subscribe function.

Handling API errors in Retrofit: Solution drawbacks

Each of the solutions I’ve mentioned have their drawbacks; some are bigger, some smaller. You need to take them into account when you handle API errors to choose the best solution for your project and make sure you know what to do if your solution doesn’t work as intended.

For example, implementing the Interceptor interface can seem like a perfect solution at first because you can handle errors at the early stages in OkHttp. However, this is where you can encounter some problems.

Each of the solutions I’ve mentioned have their drawbacks; some are bigger, some smaller. You need to take them into account when you handle API errors

The deal is that to implement error handling behavior in your app, you need to transfer the app’s Context into an OkHttpClient. Error handling behavior includes notifying the user about an error or making an additional or alternative request to the backend.

When you transfer the Context into an OkHttpClient, this can lead to unpredictable errors in the application if you change the Context. This can also result in memory leakage.

Using an RxJava2Adapter to process the errors directly in the Subscribe function is a great idea until there are more than two methods in which you need to process errors.

The best way to handle API errors

While experimenting with different solutions for API error handling, I came up with a perfect solution that involves processing errors in a reactive data flow. I achieved this using RxJava.

The idea is to get the response to our request in the form of an object with or without an error, or to receive an HTTP error as a certain type of exception. This way we can handle internal errors like we handle HTTP errors.

This is what we need to make it work.

1. First, create an object that will contain the Context and the app’s behavior in case of any errors. For this, you’ll need to implement an interface for creating different error processors:

public interface BaseView {
   Context getContext();
}

This is how I implemented the processor:

public class RxErrorHandling implements BaseView {
   private WeakReference context;

RxErrorHandling(Context context){
	this.context = new WeakReference<>(context);
}

   private Context getContext() {
       return context.get();
   }

public void exampleInnerErrorWithCode (int code){
	//in case you received an internal error code from your server, use this method to handle the error 
Log.e(“TAG”, “Inner error with code ” + code);
//You can display Toast as well, because we got Context
}

public void onTimeoutError (){
	//you process the error here if you got the TimeoutException 
Log.e(“TAG”, “TimeoutException”);
}

public void onNetworkError (){
	//if the NetworkErrorException was initialized, process the error here  
Log.e(“TAG”, “ NetworkErrorExeption”);
}
	...
}

2. At this point, we need to create a class with two methods. These methods will process the server responses and HTTP errors.

class ResponseWrapper{
	private RxErrorHandling baseView;
	
	ReponseWrapper(RxErrorHandling view){
		this.baseView = view;
	}
	//Method for handling internal errors in the response
	public handlingResponse(BaseResponse response){
		if (!resp.isSuccess()) {
		//In case there is an internal error in the response, send the error code to the view to get a reaction
			baseView.exampleInnerErrorWithCode(resp.getErrorCode);
		}
	//Here you initialize the method for generating own error
   	catchError(resp.getCode(), resp.getError());

	}

	//Method for handling HTTP errors
	public handlingException(Throwable e){
	if(e instanceof SocketTimeoutException){
		baseView.onTimeoutError ();
	}elseIf(e instanceof IOException){
		baseView.onNetworkError()
	}

//Method for generating your own exception
	private void catchError(String code, String error) {
		try {
			throw new ResponseException(error, code);
		} catch (ResponseException e) {
			throw Exceptions.propagate(e);
		}
	}
}

These are all the necessary things you need to do to get prepared for API error handling. The last thing to do is to make a request and add the following to subscribe():

  • map() – Used to check if there are any errors in the server response. If there are, this function processes them or generates an exception.
  • doOnError() – A processor that initializes with the onError method in subscribe(). This processor allows us to process the HTTP exceptions or exceptions that were created in catchError(String code, String error) in the ResponseWrapper class.
ResponseWrapper wrapper = new ResponseWrapper(this)
getUserList()	
.observeOn(AndroidSchedulers.mainThread())
// if there were no exceptions from HTTP, than map() will be initialized
.map(response -> {wrapper.testResponse(response);
   			return response;}
		)
		//if there was an HTTP or a .doOnError exception -> {
			wrapper.testExceptions(e);})
.subscribe(
users -> 
{//some actions},
throwable->
{//individual error processing}
);

This is all you need to effectively handle your API errors in the best way possible.

Conclusion

Handling API errors with Retrofit2 and RxJava is a great solution for a few reasons.

First, you get rid of excessive, repeating code. Usually an app reacts to errors in the same way, and the overall behavior to the similar errors has to be identical. For example, if you receive a 404 error, you need to show an error pop-up (e.g. Toast). In case of a 403 Forbidden error, an app should display the authorization screen.

The second reason to use this strategy is its flexibility. If you need another behavior, you can just add it to onError() in the subscribe() function.

The third reason, and the best one, is that you can treat the response like a data stream in reactive programming. Legacy AsyncTasks won’t bother you here.

I hope this article is useful for you. If you have any questions about handling API requests and errors, be sure to contact Mobindustry.

Two weeks ago, you’ve seen how to log requests and responses for debugging purposes. Requests might not finish successfully and you have to take care of failure situations. Most of the time, you need to manually apply the correct action like showing an error message as user feedback. If you get more than just the response status code, you can use the additional data to set the user in the right context and provide more information about the current error situation. That’s what this post is about: how to apply simple error handling using Retrofit 2.

Retrofit Series Overview

  • Retrofit
  • Requests
  • Responses
  • Converters
  • Error Handling
  • Logging
  • Calladapters
  • Pagination
  • File Upload & Download
  • Authentication
  • Caching
  • Testing & Mocking
  • Java Basics for Retrofit

>

Error Handling Preparations

Even though you want your app to always work like expected and there shouldn’t be any issues while executing requests. However, you’re not in control of when servers will fail or users will put wrong data which results in errors returned from the requested API. In those cases, you want to provide as much feedback to the user required to set him/her into the right context so that he/she understands what the issue is.

Before diving into the actual request which results in an error, we’re going to prepare classes to parse the response body which contains more information.

Error Object

At first, we create the error object representing the response you’re receiving from your requested API. Let’s assume your API sends a JSON error body like this:

{
    statusCode: 409,
    message: "Email address already registered"
}

If we would just show the user a generic error message like There went something wrong, he/she would immediately be upset about this stupid app which isn’t able to show what went wrong.

To avoid these bad user experiences, we’re mapping the response body to a Java object, represented by the following class.

public class APIError {

    private int statusCode;
    private String message;

    public APIError() {
    }

    public int status() {
        return statusCode;
    }

    public String message() {
        return message;
    }
}

We don’t actually need the status code inside the response body, it’s just for illustration purposes and this way you don’t need to extra fetch it from the response.

Simple Error Handler

We’ll make use of the following class only having one static method which returns an APIError object. The parseError method expects the response as parameter. Further, you need to make your Retrofit instance available to apply the appropriate response converter for the received JSON error response.

public class ErrorUtils {

    public static APIError parseError(Response<?> response) {
        Converter<ResponseBody, APIError> converter = 
                ServiceGenerator.retrofit()
                        .responseBodyConverter(APIError.class, new Annotation[0]);

        APIError error;

        try {
            error = converter.convert(response.errorBody());
        } catch (IOException e) {
            return new APIError();
        }

        return error;
    }
}

We’re exposing our Retrofit instance from ServiceGenerator via static method (if you’re not familiar with the ServiceGenerator, please read the introductory post of this series). Please bear with us that we’re using a kind of hacky style by exposing the Retrofit object via static method. The thing that is required to parse the JSON error is the response converter. And the response converter is available via our Retrofit object.

At first, we’re getting the error converter from the ServiceGenerator.retrofit() instance by additionally passing our APIError class as the parameter to the responseBodyConverter method. The responseConverter method will return the appropriate converter to parse the response body type. In our case, we’re expecting a JSON converter, because we’ve received JSON data.

Further, we call converter.convert to parse the received response body data into an APIError object. Afterwards, we’ll return the created object.

Error Handler in Action

Retrofit 2 has a different concept of handling «successful» requests than Retrofit 1. In Retrofit 2, all requests that can be executed (sent to the API) and for which you’re receiving a response are seen as «successful». That means, for these requests the onResponse callback is fired and you need to manually check whether the request is actual successful (status 200-299) or erroneous (status 400-599).

If the request finished successfully, we can use the response object and do whatever we wanted. In case the error actually failed (remember, status 400-599), we want to show the user appropriate information about the issue.

Call<User> call = service.me();  
call.enqueue(new Callback<User>() {  
    @Override
    public void onResponse(Call<User> call, Response<User> response) {
        if (response.isSuccessful()) {
            // use response data and do some fancy stuff :)
        } else {
            // parse the response body …
            APIError error = ErrorUtils.parseError(response);
            // … and use it to show error information

            // … or just log the issue like we’re doing :)
            Log.d("error message", error.message());
        }
    }

    @Override
    public void onFailure(Call<User> call, Throwable t) {
        // there is more than just a failing request (like: no internet connection)
    }
});

As you can see, we use the ErrorUtils class to parse the error body and get an APIError object. Use this object and the contained information to show a meaningful message instead of a generic error message.

Outlook

This article shows you a simple way to manage errors and extract information from the response body. Most APIs will send you specific information on what went wrong and you should make use of it.

This is just the tip of the iceberg when it comes to error handling. Within Retrofit 1, you had the opportunity to add a custom error handler. This option was removed from Retrofit 2 and we think it’s good the way it is. We’ll tell you about more advanced techniques on error handling with Retrofit 2 within a future blog post.

If you run into any issue or have a question, please let us know in the comments below or tweet us @futurestud_io.


Still Have Questions? Get Our Retrofit Book!

Retrofit Book

All modern Android apps need to do network requests. Retrofit offers you an extremely convenient way of creating and managing network requests. From asynchronous execution on a background thread, to automatic conversion of server responses to Java objects, Retrofit does almost everything for you. Once you’ve a deep understanding of Retrofit, writing complex requests (e.g., OAuth authentication) will be done in a few minutes.

Invest time to fully understand Retrofit’s principles. It’ll pay off multiple times in the future! Our book offers you a fast and easy way to get a full overview over Retrofit. You’ll learn how to create effective REST clients on Android in every detail.

Boost your productivity and enjoy working with complex APIs.

During app development, We have always faced errors and exceptions and crashes due to APIs failures. As a native mobile developer, it very important to ensure the app never crashes at the end-user. You guys also aware Retrofit with RxJava is mostly used for calling external APIs In this tutorials, I’m going to write a solution to retrofit handle error in android while integrating external APIs in a single place.

Basically, the mobile application is dependent on the API development process and doesn’t guarantee the APIs response will be always expected. If the problem is backend then they prepare a patch of containing bug fix and deployed. But in the mobile app development, it’s not happened. You depend on review times of Google Play/App Store if you need to quickly deploy a patch containing a bug fix. In this case, you also need your users to update the app after the approval to get it fixed.

The following API instability occur while integrating Rest APIs

  1. NullPointerException
  2. Manage HttpException
    • Forbidden Request
    • Internal Server Error
    • Unauthorized Exception
    • Check for “Bad Request” and throw IncorrectLoginPasswordException
    • ConnectionException – No Internet
    • Any other error is just NetworkException
  3. While APIs response format is not expected. eg, JsonSyntaxException BEGIN_OBJECT but was BEGIN_ARRAY, Expected BEGIN_OBJECT but was STRING

1. NullPointerException

NullPointerException is most common exception occurs when you performing operation of null object. Let’s suppose our app has a screen containing RecyclerView that showing feed data from a model class. The model class is simple POJO that containing the following attributes described by the API.

public class Row {

    @SerializedName("title")
    @Expose
    private String title;
    @SerializedName("description")
    @Expose
    private String description;
    @SerializedName("imageHref")
    @Expose
    private String imageHref;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getImageHref() {
        return imageHref;
    }

    public void setImageHref(String imageHref) {
        this.imageHref = imageHref;
    }
}

On the screen, we have decided to show the title with uppercase letters. like below

TextView titleView = (TextView) findViewById(R.id.tvTitle);
titleView.setText(row.getTitle().toUpperCase());

Problem Statement

The app now is working fine as expected, you submitted at Google Play and user are happy to use it. Now let’s suppose APIs stop the sending title parameter. then what happens.? The app will crash when trying to show the title because we are applying toUpperCase () method on null object.

Proposed Solution

The proposed solution validates the model before it’s sent to the view, and somehow validation failed, show the error message to the user. But runtime just checking every property against null, not a good practice. It’s affected your app performance. then how to do .?

We need to find out the way so we tell compiler at runtime which properties we want to be verified. We can do using annotations.

Annotations, a form of metadata, provide data about a program that is not part of the program itself.

Create model validator script

Go to src and create a file with IsDefined name

package com.androidwave.utils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created on : Jan 13, 2019
 * Author     : Morris
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface IsDefined {
}

In this class, we are using two annotations

  • Target(ElementType.FIELD) – That means the IsDefined annotation should be available at runtime
  • Retention(RetentionPolicy.RUNTIME) – It means the IsDefined will annotate class attributes.

Create a POJO validator class

Let’s create a POJO validator class that will receive a model object, search each attribute that annotated by IsDefined and if it has null value will throw an exception.

package com.androidwave.utils;

import android.support.annotation.NonNull;

import java.lang.reflect.Field;

/**
 * Created on : Jan 13, 2019
 * Author     : Morris
 */
public class PojoValidator {
    private Object model;

    public PojoValidator(@NonNull Object model)  {
        this.model = model;
    }

    public void validate() throws IllegalArgumentException {

        if (model == null) {
            throw new IllegalArgumentException("Model cannot be null");
        }

        final Field[] modelFields = model.getClass().getDeclaredFields();

        for (Field modelField : modelFields) {
            validateIsDefinedField(modelField);
        }
    }

    private void validateIsDefinedField(Field field) {

        if (field.isAnnotationPresent(IsDefined.class)) {

            Object attributeValue = null;
            field.setAccessible(true);

            try {
                attributeValue = field.get(model);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

            if (attributeValue == null) {
                throw new IllegalArgumentException(field + " is required");
            }

        }
    }
}

2. Manage HttpException

 subscription.add(
                service.getFeedResponse()
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .doOnTerminate(() -> {
                            if (view != null) {
                                view.onFetchDataCompleted();
                            }
                        })
                        .subscribe(feedResponse -> {
                            if (view != null) {
                                /**
                                 * Update view here
                                 */
                                view.onFetchDataSuccess(feedResponse);
                            }
                        }, error -> {
                           handleApiError(error);
                        })
        );
Definition of handle API error
 public void handleApiError(Throwable error) {
        if (error instanceof HttpException) {
            switch (((HttpException) error).code()) {
                case HttpsURLConnection.HTTP_UNAUTHORIZED:
                    mView.onError("Unauthorised User ");
                    break;
                case HttpsURLConnection.HTTP_FORBIDDEN:
                    mView.onError("Forbidden");
                    break;
                case HttpsURLConnection.HTTP_INTERNAL_ERROR:
                    mView.onError("Internal Server Error");
                    break;
                case HttpsURLConnection.HTTP_BAD_REQUEST:
                    mView.onError("Bad Request");
                    break;
                case API_STATUS_CODE_LOCAL_ERROR:
                    mView.onError("No Internet Connection");
                    break;
                default:
                    mView.onError(error.getLocalizedMessage());

            }
        }
    }

3. The APIs response format is not expected

This problem mostly occurs during development going on, So I have written a separate article with complete source code, Read here Retrofit Globally Error Handling 🙂

If you have trouble with Retrofit2 and RxJava you should doublecheck you Retrofit setup. To be honest I write the blogpost because it happend to me and I did not found a good answer on google.

A really common exception that you get when when Retrofit2 is missing the right call adapter is this:

Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Unable to create call adapter for rx.Observable<java.util.ArrayList<java.util.ArrayList<java.lang.String>>>

    for method RtiApi.getSensors

at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:720)

at retrofit2.ServiceMethod$Builder.createCallAdapter(ServiceMethod.java:234)

at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:160)

at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:166)

at retrofit2.Retrofit$1.invoke(Retrofit.java:145)

at com.sun.proxy.$Proxy0.getSensors(Unknown Source)

If you want to use Retrofit2 and RxJava you gradle or maven should include the following packages:

compile 'io.reactivex:rxjava:1.0.10'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.0'
compile 'com.squareup.retrofit2:retrofit:2.1.0'

When you create your Retrofit object don’t forget to add the RxJava call adapter, because that is the „thing“ that brings the functionality of emitting rx observables.

final Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(RtiApi.SERVICE_ENDPOINT)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

  • Retrieve cmdtcs форд ошибка
  • Retigo b1011b коды ошибок
  • Retarder perf reduced ошибка
  • Retarder inhibited renault premium ошибка
  • Ret 04009 10 ошибка ман тга