Downloading of file stops due to TimeOut using Retrofit and OkHTTPClient - android

I am using Retrofit to download files but after few seconds downloading stops by giving this error "retrofit give Thread suspension timed out: 110 during download" or mostly "JavaBinder: !!! FAILED BINDER TRANSACTION !!! (parcel size = 2840) ," , how to resolve this issue? File could be of any size 5MB,10MB and time of downloading could be any depending upon internet speed. Downloading shouldn't stop in case of latency.
Code :
public void run() {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
try {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progressListener))
.build();
}
catch (Exception e) {
e.printStackTrace();
progressListener.onError(e.getCause()+": "+e.getMessage());
}
return chain.proceed(chain.request());
}
});
AppGlobal.Log("usm_fileUrl","baseUrl= "+BASE_URL+" ,fileName= "+fileName);
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
;
Retrofit retrofit = builder.client(httpClient.build()).build();
RetrofitInterface downloadService = retrofit.create(RetrofitInterface.class);
Call<ResponseBody> call = downloadService.downloadFileByUrl(fileName);
this.notificationId = this.mNotification.createNotification(fileTitle,"Downloading...");
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, final retrofit2.Response<ResponseBody> response) {
if (response.isSuccessful()) {
Log.d(TAG, "Got the body for the file");
new AsyncTask<Void, Long, Void>() {
#Override
protected Void doInBackground(Void... voids) {
saveToDisk(response.body());
return null;
}
}.execute();
} else {
Log.d(TAG, "Connection failed " + response.errorBody());
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
t.printStackTrace();
Log.e(TAG, t.getMessage());
}
});
}

Related

okhttp get request return body is not as I expected

I use okhttp to get text of certain url.
url I try to get is
https://firebasestorage.googleapis.com/v0/b/famhouse.appspot.com/o/branchname%2Ftextfile?alt=media&token=a58b07a4-ddee-4ece-8222-0854a6c2a713
as you can see, it only have body saying "Testtest"
I get response well and I logged response.body().toString() but it says
okhttp3.internal.http.RealResponseBody#e640919
What I expect to see on log is Testtest
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext=this.getApplicationContext();
checkPermission();
OkHttpHandler okHttpHandler= new OkHttpHandler();
okHttpHandler.execute("https://firebasestorage.googleapis.com/v0/b/famhouse.appspot.com/o/branchname%2Ftextfile?alt=media&token=a58b07a4-ddee-4ece-8222-0854a6c2a713");
}
public class OkHttpHandler extends AsyncTask {
OkHttpClient client = new OkHttpClient();
#Override
protected Object doInBackground(Object[] objects) {
Request request = new Request.Builder()
.url("https://firebasestorage.googleapis.com/v0/b/famhouse.appspot.com/o/branchname%2Ftextfile?alt=media&token=a58b07a4-ddee-4ece-8222-0854a6c2a713").addHeader("Accept", "application/json")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
} else {
Log.e("dialog","response is : "+response.body().toString());
Log.e("dialog","response is : "+response.code());
}
}
});
return null;
}
}
you should use response.body().string()

more than one requested posted to server (retrofit)

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());
}

Android: OkHttp request within AsyncTask is called twice

I have a OkHttp request within an async taks doInBackgroun(), The resquest is a bit heavy and takes some time on my backend. Unfortunatly it looks like when OKHttp doesn't get an answer straight away it tries again, this makes my server blow up !
I have tried to disable this function but it seems to ignore it... What could i do ?
public class AsyncUpdateNewPatients extends AsyncTask<Object, Void, Boolean> {
private static OkHttpClient okHttpClient;
private static DatabaseHandler db;
ActivityMain activityMain;
public AsyncUpdateNewPatients (ActivityMain atv)
{
this.activityMain = atv;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
#Override
public void log(String message) {
Stormpath.logger().d(message);
}
});
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
okHttpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(httpLoggingInterceptor)
.retryOnConnectionFailure(false)
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15L, TimeUnit.SECONDS)
.writeTimeout(15L, TimeUnit.SECONDS)
.build();
db = new DatabaseHandler(activityMain);
}
#Override
protected Boolean doInBackground(Object... objects) {
List<PatientData> allNewPatients = db.getAllNewPatients();
JSONArray allNewPatientJSONArray = new JSONArray();
for (PatientData tempPatientObject : allNewPatients) {
JSONObject tempPatientJSON = new JSONObject();
try {
tempPatientJSON.put("firstName", tempPatientObject.getFirstName());
tempPatientJSON.put("lastName", tempPatientObject.getLastName());
tempPatientJSON.put("height", tempPatientObject.getHeight());
tempPatientJSON.put("weight", tempPatientObject.getWeight());
tempPatientJSON.put("vaccines", tempPatientObject.getVaccinHistory());
tempPatientJSON.put("address", tempPatientObject.getAddress());
tempPatientJSON.put("zone", tempPatientObject.getZone());
tempPatientJSON.put("id", tempPatientObject.getId());
String dateOfBirth = tempPatientObject.getDateOfBirth().get(Calendar.DAY_OF_MONTH) + "/" + tempPatientObject.getDateOfBirth().get(Calendar.MONTH) + "/" + tempPatientObject.getDateOfBirth().get(Calendar.YEAR);
tempPatientJSON.put("dob",dateOfBirth);
} catch (JSONException e) {
e.printStackTrace();
}
allNewPatientJSONArray.put(tempPatientJSON);
}
if(allNewPatients.size() > 0){
JSONObject bodyJSON = new JSONObject();
try {
bodyJSON.put("allNewPatients", allNewPatientJSONArray);
} catch (JSONException e) {
e.printStackTrace();
}
final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
final RequestBody body = RequestBody.create(JSON, String.valueOf(bodyJSON));
Request request = new Request.Builder()
.url(activityMain.getString(R.string.main_url) + "/api/syncFromOffLine")
.headers(buildStandardHeaders(Stormpath.accessToken()))
.post(body)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.d("DEBEUG", "error: " + e.getMessage());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if(response.code() == 200){
Log.d("DEBEUG", "response: " + response.body().string());
} else {
Log.d("DEBEUG", "there was an error: " + response.message().toString());
}
}
});
}
return true;
}

retrofit calling json data but its response show null

Here is my code any one help, why it shows response is null? There is some mistake which I cannot found.
public void getAllTasksWithSuccess(){
String url = ""+ RetrofitClient.baseURL +"here is my service code ";
RetrofitClient.createRetrofitInstance();
Call<ResponseBody> call = RetrofitClient.getCallObject("getTodaysTask",url);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
Log.i("TAG",response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i("tag2", "Failed : " + t.getMessage());
}
});
}
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String okhttp3.ResponseBody.string()' on a null object reference
at com.ra.ra.DashboardFragments.FragmentTasks$2.onResponse(FragmentTasks.java:83)
Add below class ServiceGenerator:
public class ServiceGenerator {
public static final String API_BASE_URL = AppConstants.BASE_URL;
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
public static Retrofit retrofit = null;
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static Retrofit retrofit() {
retrofit = builder.client(httpClient.build()).build();
return retrofit;
}
}
And use below ErrorUtils class to parse your response's errorBody:
public class ErrorUtils {
public static ResponseBody parseError(Response<?> response) {
Converter<ResponseBody, ResponseBody> converter =
ServiceGenerator.retrofit()
.responseBodyConverter(ResponseBody.class, new Annotation[0]);
ResponseBody error;
try {
error = converter.convert(response.errorBody());
} catch (IOException e) {
return new ResponseBody();
}
return error;
}
}
And now in your onResponse do as below:
public void getAllTasksWithSuccess(){
String url = ""+ RetrofitClient.baseURL +"here is my service code ";
RetrofitClient.createRetrofitInstance();
Call<ResponseBody> call = RetrofitClient.getCallObject("getTodaysTask",url);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response.isSuccessful()){
// here your response.body() will not be null
}else{
// here your response.body() will be null
// and here you might get your response in response.errorBody();
ResponseBody res= ErrorUtils.parseError(response);
System.out.println("Response is:"+ res.toString());
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i("tag2", "Failed : " + t.getMessage());
}
});
}

Caching with retrofit 2.0 and rxjava 2 with okhttp3

I'm trying to perform offline cashing when internet connection is lost so that i can display data from cache . here is what I've done till now .
my question is how can make my observable return the cached arraylist of data instead of just returning error?
my service generator :
public class ServiceGenerator {
public static final String API_BASE_URL = UrlManager.BASE_URL_API;
private static final String CACHE_CONTROL = "Cache-Control";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60,TimeUnit.SECONDS)
.readTimeout(60,TimeUnit.SECONDS);
private static Gson gson = new GsonBuilder()
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()));
private static Retrofit retrofit;
public static Gson getGson() {
return gson;
}
public static void setup() {
httpClient.addInterceptor(provideOfflineCacheInterceptor());
httpClient.addInterceptor(new AddCookiesInterceptor()); // VERY VERY IMPORTANT
httpClient.addInterceptor(new ReceivedCookiesInterceptor()); // VERY VERY IMPORTANT
httpClient.addInterceptor( provideHttpLoggingInterceptor() );
httpClient.addNetworkInterceptor(new StethoInterceptor());// Stetho
httpClient.addNetworkInterceptor(provideCacheInterceptor());
httpClient.cache(provideCache());
OkHttpClient client = httpClient.build();
retrofit = builder.client(client).build();
}
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null);
}
public static <S> S createService(Class<S> serviceClass, final String authToken) {
if (authToken != null) {
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", authToken)
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
}
return retrofit.create(serviceClass);
}
public static Interceptor provideCacheInterceptor() {
return new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
// re-write response header to force use of cache
CacheControl cacheControl = new CacheControl.Builder()
.maxAge(2, TimeUnit.MINUTES)
.build();
return response.newBuilder()
.header(CACHE_CONTROL, cacheControl.toString())
.build();
}
};
}
public static Interceptor provideOfflineCacheInterceptor() {
return new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!UruzApplication.hasNetwork()) {
CacheControl cacheControl = new CacheControl.Builder()
.maxStale(7, TimeUnit.DAYS)
.build();
request = request.newBuilder()
.cacheControl(cacheControl)
.build();
}
return chain.proceed(request);
}
};
}
private static Cache provideCache() {
Cache cache = null;
try {
cache = new Cache(new File(UruzApplication.getInstance().getCacheDir(), "http-cache"),
10 * 1024 * 1024); // 10 MB
} catch (Exception e) {
Timber.e(e, "Could not create Cache!");
}
return cache;
}
private static HttpLoggingInterceptor provideHttpLoggingInterceptor ()
{
HttpLoggingInterceptor httpLoggingInterceptor =
new HttpLoggingInterceptor( new HttpLoggingInterceptor.Logger()
{
#Override
public void log (String message)
{
Timber.d( message );
}
} );
httpLoggingInterceptor.setLevel( true ? HEADERS : NONE );
return httpLoggingInterceptor;
}
}
my observer :
public static Observable<List<WeekDietPlan>>
fetchPackageWeeksDaysDietPlan(int traineeId) {
DietService requestService = ServiceGenerator.createService(DietService.class);
return requestService.getPackageWeekDaysDietPlan(UrlManager.getTraineeDietPackageDetailsUrl(),
traineeId)
.flatMap(new Function<JsonElement, Observable<List<WeekDietPlan>>>() {
#Override
public Observable<List<WeekDietPlan>> apply(JsonElement jsonElement) throws Exception {
JsonObject asJsonObject = jsonElement.getAsJsonObject();
String result = asJsonObject.get(UrlManager.ResultTypes.RESULT).getAsString();
Timber.d(TAG, "result Tag" + result);
if (UrlManager.ResultTypes.isError(result) || UrlManager.ResultTypes.isFailure(result)) {
String errorMessage = asJsonObject.get(UrlManager.ResultTypes.RESULT_ERROR_MESSAGE).getAsString();
return Observable.error(new Exception(errorMessage));
}
if (UrlManager.ResultTypes.isSucess(result)) {
if (!GsonHelper.isNull(asJsonObject.get(UrlManager.ResultTypes.RESULT_DATA)) && asJsonObject.get(UrlManager.ResultTypes.RESULT_DATA).isJsonArray()) {
return Observable.just(WeekDietPlan.PackageDietWeekDaysListParser.fromJsonElement(asJsonObject.getAsJsonArray(UrlManager.ResultTypes.RESULT_DATA)));
} else {
return Observable.error(new Exception("Data is empty"));
}
}
if (UrlManager.ResultTypes.isLogin(result)) {
return Observable.error(new SessionTimeoutException());
}
return Observable.error(new Exception("Unkown Tag"));
}
})
.observeOn(AndroidSchedulers.mainThread());
}
my api call :
private void retrievePackageWeekDaysPlan() {
hideConnectionErrorLayout();
if (!swipRefreshLayout_reLoad.isRefreshing()) {
swipRefreshLayout_reLoad.setRefreshing(true);
}
DietNetworkCall.fetchPackageWeeksDaysDietPlan(1).subscribe(new Observer<List<WeekDietPlan>>() {
#Override
public void onSubscribe(Disposable d) {
Timber.d(TAG, "onSubscribe() called with: d = [" + d + "]");
compositeSubscription.add(d);
}
#Override
public void onNext(List<WeekDietPlan> list) {
Timber.d(TAG, "onNext() called with: value = [" + list.size() + "]");
swipRefreshLayout_reLoad.setRefreshing(false);
hideConnectionErrorLayout();
if (list.size() == 0)
{
Toast.makeText(getContext(), R.string.noDietPackageAvailable, Toast.LENGTH_SHORT).show();
}
bindRecyclerData(list);
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
Timber.d(TAG, "onError() called with: e = [" + e + "]");
swipRefreshLayout_reLoad.setRefreshing(false);
if (e instanceof IOException) {
Toast.makeText(getContext(), R.string.connectionError, Toast.LENGTH_SHORT).show();
} else if (e instanceof NullPointerException) {
} else if (e instanceof SessionTimeoutException) {
AuthenticationManager.logOut();
} else {
Toast.makeText(getContext(),
e.getMessage(),
Toast.LENGTH_SHORT).show();
}
}
#Override
public void onComplete() {
Log.d(TAG, "onComplete() called");
}
});
}
I know this is late, and directed towards future folks.
There is a need to create a Network Interceptor like this
public abstract class NetworkConnectionInterceptor implements Interceptor {
public abstract boolean isInternetAvailable();
public abstract void onInternetUnavailable();
public abstract void onCacheUnavailable();
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!isInternetAvailable()) {
onInternetUnavailable();
request = request.newBuilder().header("Cache-Control",
"public, only-if-cached, max-stale=" + 60 * 60 * 24).build();
Response response = chain.proceed(request);
if (response.cacheResponse() == null) {
onCacheUnavailable();
}
return response;
}
return chain.proceed(request);
}
}
Then add it with your okhttp builder. You can refer to this link.
One more you should take care is to check your response "Cache-control" header. Its value has to be like this "max-age=2592000".
To return the cached data instead of the error, you could use the onErrorReturn operator that:
Instructs an Observable to emit an item (returned by a specified
function) rather than invoking onError if it encounters an error.
List of the different operators to recover on error: https://github.com/ReactiveX/RxJava/wiki/Error-Handling-Operators

Categories

Resources