I'm using retrofit to fetch some data from a remote server, when the response code is something other than 200 for success, the body returns as null.
I found out in this case I should get my result from response.errorBody() but it returned in a raw JSON form of course, is there anyway to map it automatically using the GsonConverterFactory that I included in my retrofit instance?
mApiServices.register(builder.build()).enqueue(new Callback<LoginModel>() {
#Override
public void onResponse(Call<LoginModel> call, Response<LoginModel> response) {
if (response.code() == 200 && response.body() != null && response.body().getStatus() == 1) {
LoginModel.Data data = response.body().getData();
mDataLiveData.setValue(data);
saveToSharedPref(data);
} else {
String errorBody = null;
try {
errorBody = response.errorBody().string();
} catch (IOException e) {
e.printStackTrace();
}
}
resetIsLoading();
}
#Override
public void onFailure(Call<LoginModel> call, Throwable t) {
mGeneralError.setValue(t.getMessage());
resetIsLoading();
}
});
And here's how I instantiated the Retrofit instance
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder().addHeader("lang", PreferenceUtils.getLocaleKey(context)).build();
return chain.proceed(request);
}
}).build();
retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
Related
I want to use retrofit for fetching data from my server. My server send data as a string json.
I create a server like this:
public class ServiceGenerator {
public static final String BASE_URL = "http://192.168.100.73/ChartReport/Service1.svc/";
static OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(1, TimeUnit.MINUTES)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.build();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create());
private static Retrofit retrofit = builder.build();
public static <S> S createService(Class<S> serviceClass) {
return retrofit.create(serviceClass);
}
}
And then i have created client like blow:
public interface IReportCLient {
#POST("json/GetDataReport")
Call<ResponseBody> getReporst();
}
And I have used into my activity :
IReportCLient service = ServiceGenerator.createService(IReportCLient.class);
Call<ResponseBody> reporst = service.getReporst();
reporst.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
JsonObject post = new JsonObject().get(response.body().string()).getAsJsonObject();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
When I run my app in debug mode for first time i fetch my data by this command:
response.body().string()
but immediately my result is null when i run response.body().string() again??
What is happens?
string() method can only be called once on RequestBody. So it will return empty string if you try to call it again. This is true for debugging as well. If you try to evaluate expressions response.body().string() while debugging, your actual methods will get empty string.
An HTTP response. Instances of this class are not immutable: the
response body is a one-shot value that may be consumed only once and
then closed. All other properties are immutable.
https://square.github.io/okhttp/3.x/okhttp/okhttp3/Response.html
Read this as well https://stackoverflow.com/a/32307866/6168272
This is how I get JsonObject from my response object. You can give it a try.
private JSONObject parseJsonFromResponse(Response response) {
ResponseBody responseBody = response.body();
if (responseBody != null) {
try {
return new JSONObject(responseBody.string());
} catch (JSONException | IOException e) {
e.printStackTrace();
return new JSONObject();
}
} else return new JSONObject();
}
Below are the files for retrofit.
While passing the data in the form of JSON I am getting a null response.
Could anyone guide where can be the issue occurring?
I am trying to post the data in the form of JSON using the retrofit library. Can you suggest me the right approach?
My code:
public class ApiSellarClient {
public static final String BASE_URL = "Constant.BASE_URL";// it is from constant file..
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(BASE_URL)
.client(client)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
public class ApiSellarConnection {
public static Call<String> getSignInData(JSONObject json) {
return ApiSellarClient.getClient().create(ApiSellarInterface.class).getSignInData(json);
}
}
public interface ApiSellarInterface {
#Headers("Content-Type: application/json")
#POST("integration/customer/token")
Call<String> getSignInData(#Body JSONObject json);
}
// Below is the controller class.
JSONObject paramObject = new JSONObject();
try {
paramObject.put("username", etUserName.getText().toString());
paramObject.put("password", etPassword.getText().toString());
ApiSellarConnection.getSignInData(paramObject).enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
Log.d("tag", "helper" + response.body());
}
#Override
public void onFailure(Call<String> call, Throwable t) {
}
});
} catch (JSONException e) {
e.printStackTrace();
}
I am using retrofit to post the request to server but it is posting data twice. I have checked code, I made only on call. I know retrofit trying to connect server again and again until it connected or timeout but if once data posted to server and I get the response from server than why retrofit making again call for the same.
Call<LoanSaveResponse> call = apiService.saveLoan(loan);
call.enqueue(new retrofit2.Callback<LoanSaveResponse>() {
#Override
public void onResponse(Call<LoanSaveResponse> call, Response<LoanSaveResponse> response) {
customProgressBar.stopProgressBar();
Log.e(" response", new Gson().toJson(response));
if (response != null) {
if (response.body() != null) {
// Showing Alert Message
showDialog(response.body().loan_id);
}
}
}
#Override
public void onFailure(Call<LoanSaveResponse> call, Throwable t) {
customProgressBar.stopProgressBar();
Log.e("Failed", t.toString());
}
});
}
public class ApiClient {
/*http://172.16.40.1:8080/loyalty/*/
//:http://54.83.7.62:8080/loyalty/userAnswer
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit==null) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder()
.baseUrl(GlobalBaseUrl.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
}
return retrofit;
}
}
For Retrofit 2
Define a listener in your web service instance:
public interface OnConnectionTimeoutListener {
void onConnectionTimeout();
}
Add an interceptor to your web service:
public WebServiceClient() {
OkHttpClient client = new OkHttpClient();
client.setConnectTimeout(10, TimeUnit.SECONDS);
client.setReadTimeout(30, TimeUnit.SECONDS);
client.interceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
return onOnIntercept(chain);
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
webService = retrofit.create(WebService.class);
}
Enclose your intercept code with the try-catch block and notify the listener when an exception happens:
private Response onOnIntercept(Chain chain) throws IOException {
try {
Response response = chain.proceed(chain.request());
String content =
UtilityMethods.convertResponseToString(response);
Log.d(TAG, lastCalledMethodName + " - " + content);
return;
response.newBuilder().body
(ResponseBody.create
(response.body().contentType(), content))
.build();}
catch (SocketTimeoutException exception) {
exception.printStackTrace();
if(listener != null)
listener.onConnectionTimeout();
}
return chain.proceed(chain.request());
}
In my application I want to create a Login/Register page.
In the login page I send the Username, Password, Token from client to Server.
I should get Username and Password from USER, and get Token from HEADER of Request.
For connect client to server I use Retorfit 2.2.0 library.
Code from the Interface class :
#POST("User/Authenticate")
Call<LoginResponse> getLoginResponse(#Header("Token") String token, #Body LoginDatum loginDatum);
Code within the Activity :
public void getLogin(String username, String password) {
final LoginDatum loginDatum = new LoginDatum();
loginDatum.setUsername(username);
loginDatum.setPassword(password);
InterfaceApi api = ApiClient.getClient().create(InterfaceApi.class);
Call<LoginResponse> call = api.getLoginResponse(sendToken, loginDatum);
Log.e("tokenTAG", "Token : " + sendToken);
call.enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
LoginResponse loginResponse = response.body();
String token = response.headers().get("Token");
if (token != null) {
sendToken = token;
Log.e("tokenTAG", "Token : " + sendToken);
}
if (loginResponse.getStatusCode() == 200) {
Toasty.success(context, context.getResources().getString(R.string.welcome) + " " +
loginResponse.getData().getName(), Toast.LENGTH_LONG, true).show();
} else {
Toasty.error(context, loginResponse.getStatusMessage() + "", Toast.LENGTH_LONG, true).show();
}
loadProgress.get(0).setVisibility(View.GONE);
loginBtn.setVisibility(View.VISIBLE);
btnShadow.setVisibility(View.VISIBLE);
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
loadProgress.get(0).setVisibility(View.GONE);
loginBtn.setVisibility(View.VISIBLE);
btnShadow.setVisibility(View.VISIBLE);
Toasty.error(context, context.getResources().getString(R.string.failRequest),
Toast.LENGTH_LONG, true).show();
}
});
}
And show me this in LogCat :
tokenTAG: Token : null
tokenTAG: Token : MKGKFPOVRMU4MRK0STNDO20RA2MPEWT7Y1N2WUM5QLIXJX2TEOM9APGUTYJMD8R42WFVESD8GRXCTCINA2LZKU7JV2I7KA2R4N5W
But when I want to send the token with this code : Call<LoginResponse> call = api.getLoginResponse(sendToken, loginDatum); it shows me null.
I have use this line : Call<LoginResponse> call = api.getLoginResponse(sendToken, loginDatum); to generate the request callBack, although this line Token is not NUll.
How can I fix it?
if you use Retrifit get onNetwork request,in order to add Header to your requese,you must be write an Intercepter.
just replace getClient menthod with this one
public static Retrofit getClient(final Context context) {
if (retrofit == null) {
Log.d("AuthTokenTest", "getClient: null");
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
dispatcher = new Dispatcher();
httpClient.dispatcher(dispatcher);
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Log.d("INTERCEPTOR", original.url().toString());
//System.out.print(original.toString());
Request request;
user=User.getLoggedInUserInstance(context);
String authToken="";
if(user!=null)
authToken=user.getAuthToken();
Log.d("AuthTokenTest", "intercept: authtoken:"+authToken);
request = original.newBuilder()
.header("X-AUTH-TOKEN", authToken)
.header("x-requested-with", "XMLHttpRequest")
.method(original.method(), original.body())
.build();
okhttp3.Response response = chain.proceed(request);
Log.d("INTERCEPTOR-", "response_code: "+response.code());
// Log.d("INTERCEPTOR", response.body().string());
return response;
}
});
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
if(BuildConfig.DEBUG){
//print the logs in this case
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
}else{
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
}
httpClient.addInterceptor(loggingInterceptor);
OkHttpClient client = httpClient.build();
Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.TRANSIENT)
.setLenient()
.create();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
let me know if this solution works or not
I am trying to use an Interceptor to add a header when using Retrofit. I think I have created my Interceptor in the right way but I don't know what should I do to call it and connect it with my GET Retrofit method.
This is my Interceptor:
public class HeaderInterceptor
implements Interceptor {
#Override
public Response intercept(Chain chain)
throws IOException {
Request request = chain.request();
request = request.newBuilder()
.addHeader(Constants.VersionHeader.NAME, Constants.VersionHeader.VALUE)
.addHeader("Authorization", "Bearer " + token)
.addHeader("Origin","MY URL")
.build();
Response response = chain.proceed(request);
return response;
}
}
And this is my interface:
public interface CategoryService {
#GET("/v3/projects/{projectId}/categories/")
Call<ArrayList<Category2>> getProjectCategories(#Path("projectId") String projectId);
}
I also have this client which I don't know if I should use it anymore considering that I am using an Interceptor:
public class CategoryClient {
public static final String BASE_URL = "MY URL";
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;
}
}
So I have this GET method getProjectCategories, where I pass the projectID and it returns the contents. What I want to know is how can I call the method using the Interceptor and be able to get the results from the request.
I was able to fix my problem by creating a method called SendNetworkRequest sending the projectId as a parameter, and inside this class I created my OkHttpClient, my Interceptor and my retrofit builder to handle everything that i needed.
private void SendNetworkRequest(String projectID) {
OkHttpClient.Builder okhttpBuilder = new OkHttpClient.Builder();
okhttpBuilder.addInterceptor(new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder newRequest = request.newBuilder().header("Authorization", "Bearer " + token);
return chain.proceed(newRequest.build());
}
});
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("MY URL")
.client(okhttpBuilder.build())
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
CategoryService category = retrofit.create(CategoryService.class);
Call<ArrayList<Category2>> call = category.getProjectCategories(projectID, token);
call.enqueue(new Callback<ArrayList<Category2>>() {
#Override
public void onResponse(Call<ArrayList<Category2>> call, Response<ArrayList<Category2>> response) {
listCategories = response.body();
listCategories.remove(response.body().size() - 1);
if (response.body().size() > 0){
add_category_layout.setVisibility(View.VISIBLE);
layout_bar.setVisibility(View.VISIBLE);
message_body.setVisibility(View.INVISIBLE);
message_title.setVisibility(View.INVISIBLE);
edit_image.setVisibility(View.INVISIBLE);
adapter2 = new CategoryAdapter2(getApplicationContext(), listCategories);
recyclerView.setAdapter(adapter2);
recyclerView.setVisibility(View.VISIBLE);
}
}
#Override
public void onFailure(Call<ArrayList<Category2>> call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
}