Retrofit getMessage in onFailure returns null - android

I use these libraries in my app:
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
It is my RetrofitClientInstance class implementations:
public class RetrofitClientInstance {
private static Retrofit retrofit;
private static final String BASE_URL = "my basic url";
public static Retrofit getRetrofitInstance() {
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
}
return retrofit;
}
}
Until this morning it was no problem but from this morning it is not working and getMessage in onFailure returns null and t.toString() returns java.net.SocketTimeoutException. (It is Ok on postman still).
#Override
public void onFailure(#NonNull Call<List<Ad>> call, #NonNull Throwable t) {
call.clone().enqueue(this);
Log.e("error in SplashScreen", "!!" + t.getMessage());
}
What is the problem?

From the javadoc for retrofit
onFailure(Call<T> call, Throwable t)
Invoked when a network exception occurred talking to the server or when an unexpected exception occurred creating the request or processing the response.
If your specific request is okay on POSTMAN, then there is no chance that it could be going on the onFailure() callback unless:
The android client is not connected to the Internet.
The Base URL or the endpoint is wrong.
You are calling for a resource ie. List<Ad>that the endpoint cannot return.
Your Request type (POST/GET/PUT/..) is wrong.
The response is not available within the default timeout declared in the api client. code: new OkHttpClient.Builder().connectTimeout(100, TimeUnit.SECONDS) //connect timeout
In addition to that I only do the following in my onFailure() callback and it works like a charm:
Log.e(TAG, t.getLocalizedMessage());
Log.e(TAG, t.getMessage());
t.printStackTrace();

Related

Retrofit returns HTTP 401 for call running in background

I have a strange problem with one of my retrofit call,it works fine when the app is in the background(recent list)
I have a call through which i update my widget data,the problem is when the app is cleared of from the recent list,the call gives HTTP 401 unauthorized response.
however i pass the same bearer token with it.
please have a look at the code and suggest some help
public static OkHttpClient getOkhttpClient() {
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("Authorization", "Bearer " + TokenGenerator.getToken())
.build();
return chain.proceed(newRequest);
}
}).build();
return client;
}
public static Retrofit getClient() {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(getOkhttpClient())
.addConverterFactory(JacksonConverterFactory.create())
.build();
}
return retrofit;
}

Retrofit returns 404 respone code

ApiClient.java class -
public class ApiClient {
public static final String BASE_URL = "https://jsonplaceholder.typicode.com/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
Interface -
public interface ApiInterface {
#POST("posts/1")
Call<ModelClass> savePost();
}
In onCreate of activity -
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<ModelClass> call = apiService.savePost();
call.enqueue(new Callback<ModelClass>() {
#Override
public void onResponse(Call<ModelClass>call, Response<ModelClass> response) {
Log.i(TAG,"response is "+response.body());
Log.i(TAG,"response code is "+response.code());
}
#Override
public void onFailure(Call<ModelClass>call, Throwable t) {
// Log error here since request failed
Log.i(TAG, t.toString());
}
});
Dependencies which I included in Gradle -
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
why retrofit returns 404 response code.Is there any problem with the above code?
Thanks in advance.
Bro your code is fine problem is with api.
When i hit your api in post method on POSTMAN its showing 404 Not Found so please check your server
But its not showing the empty json object as body so maybe there are parameters missing and you are using 404 status for showing this which is a bad practice show 404 only when this api doesnt exist and use other error codes like 409,422 for this type of action so you are more clear about response
What you should check if the endpoint is correct , or the url I had the same problem my BASE_URL was right but the endpoint not then I I was getting the 404 error.
Hope this helps .
You can check in the postman for status server.
Usually there is response in the body but the status maybe still 404, so it will be errorbody not response.body.

How can I debug my retrofit API call?

I'm using retrofit to get some data from the Flickr api. The method I'm making the call in looks like this:
public static List<String> getImageIds(int size) {
Call<PhotosList> call = flickrService.getPhotos(apiKey, format, "1");
Log.d("TEMP_TAG", "photo url: " + call.request().url().toString());
photoIds = new ArrayList<String>();
call.enqueue(new Callback<PhotosList>(){
#Override
public void onResponse(Call<PhotosList> call, Response<PhotosList> response) {
Log.d("TEMP_TAG", "it's getting here");
PhotosList photosList = response.body();
List<Photo> photos = photosList.getPhotos().getPhoto();
for(Photo photo : photos) {
Log.d("TEMP_TAG", "adding photo id to list: " + photo.getId());
photoIds.add(photo.getId());
}
}
#Override
public void onFailure(Call<PhotosList> call, Throwable t) {
// TODO: Clean up
Log.d("TEMP_TAG", "photoId: ");
}
});
Log.d("TEMP_TAG", "it's getting here too");
return photoIds;
}
However it is never getting into the onResponse() method. The first log statement within onResponse() never prints, neither does the log statement in onFailure(). When I try entering the URL that is returned by call.request().url().toString() in the browser it works fine, and I get the expected JSON. Why is my enqueue() method never firing?
Thanks for any help!
Use HttpLoggingInterceptor along with Retrofit.
If this helps, add this inside your build.gradle -
//Retrofit and OkHttp for Networking
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
//Logging Network Calls
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
Inside your APIClient class add this -
public class ApiClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
if(retrofit==null){
retrofit = new Retrofit.Builder()
.baseUrl(BuildConfig.baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
}
return retrofit;
}
}
Kotlin Code
val interceptor : HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val client : OkHttpClient = OkHttpClient.Builder().apply {
addInterceptor(interceptor)
}.build()
fun getService(): Service {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(LiveDataCallAdapterFactory())
.client(client)
.build()
.create(Service::class.java)
}
And you will be able to log the Retrofit Network calls that you make.
Let me know if you need more information.
An OkHttp interceptor which logs HTTP request and response data.
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(Level.BASIC);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.build();
You can change the log level at any time by calling setLevel.
There are 4 levels: NONE, BASIC, HEADERS, BODY
To log to a custom location, pass a Logger instance to the constructor.
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new
Logger() {
#Override public void log(String message) {
Log.d(TAG, "message: ");
}
});
From Gradle
compile 'com.squareup.okhttp3:logging-interceptor:(insert latest version)'
Follow this reference
EDITED: I also found this library which has a very nice structure and clean log. Try it!!
You can use the following class to log API calls
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
object HTTPLogger {
fun getLogger(): OkHttpClient {
/*
* OKHTTP interceptor to log all API calls
*/
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.build()
return client
}
}
You can then call this class in your retrofit instance class like this
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClientInstance {
private var retrofit: Retrofit? = null
val retrofitInstance: Retrofit?
get() {
if (retrofit == null) {
retrofit = Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(HTTPLogger.getLogger())
.build()
}
return retrofit
}
}
The dependency required is
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'

How to handle No Network connection using Retrofit 2.0 in Android?

I am using Retrofit 2.0 library in my android application by adding it into build.gradle file
// retrofit, gson
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
related code is given below
ApiInterface.java
public interface ApiInterface {
#GET("contacts/")
Call<ContactsModel> getContactsList();
}
ApiClient.java
public class ApiClient {
public static final String BASE_URL = "http://myexamplebaseurl/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
MainActivity.java
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<ContactsModel> call = apiService.getContactsList();
call.enqueue(new Callback<ContactsModel>() {
#Override
public void onResponse(Call<ContactsModel> call, Response<ContactsModel> response) {
if(response.isSuccessful()){
/*here is my data handling*/
}
}
#Override
public void onFailure(Call<ContactsModel> call, Throwable t) {
/*It is the request failure case,
I want to differentiate Request timeout, no internet connection and any other reason behind the request failure
*/
}
});
if we get status code as 4xx or 5xx even though onResponse() will called, so there we need handle that condition also.
Here my question is, How to differentiate reason for request failure i.e onFailure() by using Retrofit 2.0 in Android?
Here my question is, How to differentiate reason for request failure
by using Retrofit 2.0 in Android?
if you have a 4xx or 5xx error, onResponse is still called. There you have to check the response code of the code to check if everything was fine. E.g
if (response.code() < 400) {
in case of No Network connection, onFailure is called. There you could check the instance of the throwable. Typically an IOException

Retrofit 2 enqueue method running 2 times

I am new to Retrofit Library. I am working on an app in which I've to make multiple API calls, but this problem sticks me when I tried to make my first API Call...
I am facing the issue that whenever I used to call retrofit's Asynchronous call method then the functionality inside onResponse method is running 2 times...
This is my code when I am calling the API call asynchronously...
final ApiModule apiService = ApiServiceGenerator.createService(ApiModule.class);
Call <ConfigResponse> call = apiService.getConfig();
call.enqueue(new Callback<ConfigResponse>() {
#Override
public void onResponse(Call<ConfigResponse> call, Response<ConfigResponse> response) {
try {
if (response.isSuccessful()) {
Log.e("MyTag", "This is running");
}
} catch(Exception e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ConfigResponse> call, Throwable t) {
e.printStackTrace();
}
});
As soon as I run the App on the device and when I see my android studio's logger, its is showing me the log message as -
E/MyTag: This is running
E/MyTag: This is running
It seems here that its running for 2 times..!!
I cannot understand that why is it running 2 times.
Please help me out with this...
Just for more help...
I've implemented my code like this.
ApiModule Interface (where I defined my API Call URLs)
public abstract interface ApiModule {
#GET("config")
Call<ConfigResponse> getConfig();
}
ApiServiceGenerator goes like this -
public class ApiServiceGenerator {
public static final String API_BASE_URL = "https://www.example.com/";
private static OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder().addHeader("App-Secret", "some-secret-key").build();
return chain.proceed(newRequest);
}
})
.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) // Just For logging
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.build();
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new ArrayAdapterFactory())
.create();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(new GsonBuilder().registerTypeAdapterFactory(new ArrayAdapterFactory()).create()));
public static <S> S createService(Class<S> serviceClass) {
Retrofit retrofit = builder.client(httpClient).build();
return retrofit.create(serviceClass);
}
public static Retrofit retrofit() { // For Error Handing when non-OK response is received from Server
OkHttpClient httpClient = new OkHttpClient.Builder().build();
OkHttpClient client = httpClient;
return builder.client(client).build();
}
}
Finally I resolved my problem..
Its not the problem of the Retrofit library..!!
Actually its my bad. I am opening the fragment twice (which I don't know before answering this question)...
That's why the code inside the fragment is running twice which makes me think as retrofit response is running twice...
In my case, I was using interceptors, inside one of them I called chain.proceed() twice. maybe you should check that too. this will not appear on your log. Use Stetho to check exactly how many times a call is being made.
Don't call any function from retrofit that returns "Response" more than once inside any of your interceptors.
In my case its called twice due to
chain.proceed(request) called twice in same Interceptor
eg
class ErrorInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request: Request = chain.request()
chain.proceed(request)
val response = chain.proceed(request) // it called twice in this Interceptor
when (response.code()) {
}
return response
}
}

Categories

Resources