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();
}
Related
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;
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());
}
I am new in using retrofit in android. I have a get request which is working in a good manner but I want to include the value of shared preference in the endpoint of the URL. Suppose my end point Url is :
public interface Data{
#GET("/myphone/extra/pull/Sharedpreferencevalue") //add shared preference value here
}
Can I do this in retrofit or I have to do with some other way? or how it can be done in retrofit?
You can add parameters dynamically as follows:
#GET("/myphone/extra/pull/{Sharedpreferencevalue}")
Call<YourResponseClass> getData(#Path("Sharedpreferencevalue") String value);
You can use #Path annotation to programmatically add value to the endpoint, and do something like this in your with retrofit Service interface:
#GET("/myphone/extra/pull/{sharedprefValue}")
Call<EntityName> getPref(#Path("sharedprefValue") String pref);
Use urls dynamically to retrofit2 as follows.
in your interface
#GET
public Call<ResponseBody> fetchMileage(#Url String url);
use it this way
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(ROOT_URL)
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.client( httpClient.build()).build();
MyInterface myInterface = retrofit.create(MyInterface.class);
Call<ResponseBody> result = myInterface.fetchMileage(endpointUrl);
result.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
String output ="";
if (response.isSuccessful()) {
try {
output = response.body().string();
}catch (IOException e)
{
e.printStackTrace();
}
}else{
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable throwable) {
//Toast.makeText(context,"Error "+throwable.getMessage(),Toast.LENGTH_LONG).show();
throwable.printStackTrace();
}
});
I am fetching images from a REST API and assigning them to an Array successfully on onResponse. However, I am unable to pass a random image to another class due to it always returns empty.
How do I make it? Please help me.
My function as follows:
private String[] headerImages = new String[10];
public String fetchOnlyImages(String url) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.authenticator(new Authenticator() {
#Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic(USERNAME, PASSWORD);
return response.request().newBuilder()
.header(AUTH, credential).build();
}
}).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(NewsService.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
final NewsService newsService = retrofit.create(NewsService.class);
Call<HolderNode> holderNodeCall = newsService.holderNode(url);
holderNodeCall.enqueue(new Callback<HolderNode>() {
#Override
public void onResponse(Call<HolderNode> call, retrofit2.Response<HolderNode> response) {
if (response.isSuccessful()) {
HolderNode holderNode = response.body();
MainNode mainNode;
try {
for (int i = 0; i < holderNode.nodes.size(); i++) {
mainNode = holderNode.nodes.get(i);
if (mainNode.node.image != null) {
String imageUrl = mainNode.node.image.src.substring(0, mainNode.node.image.src.length() - 13);
headerImages[i] = imageUrl;
}
}
} catch (Exception ignored) {
}
}
}
#Override
public void onFailure(Call<HolderNode> call, Throwable t) {
}
});
Random random = new Random();
int chosenNumber = random.nextInt(headerImages.length);
return headerImages[chosenNumber];
}
}
You can't return from this method - that's not how async code works.
You must continue your processing from within the onResponse method, after you are guaranteed to have an array.
Your issue is that the null array is returned before the onResponse is ever entered
You can provide a parameter for a callback into fetchOnlyImages, and pass that through to the network call