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
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;
I have a function inside a aar module that needs to wait the onResponse() or onError() response by using AndroidNetworking. The output is the return executes first before waiting on whatever response it will received. I'm having a problem on waiting the response to return on my app. I also used synchronized on the function. this is the code on my module
public static synchronized String getActivationData(final Context context, final String api, final String base64Header, final String endpoint, final JSONObject body) {
final String[] result = {null};
new Thread(new Runnable() {
#Override
public void run() {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
String baseURL = null;
if (api.equalsIgnoreCase("LOCAL")) {
baseURL = Environments.getMarkLocalAPI();
} else if (api.equalsIgnoreCase("DEVELOPMENT")) {
baseURL = Environments.getDevelopmentAPI();
} else if (api.equalsIgnoreCase("STAGING")) {
baseURL = Environments.getStagingAPI();
} else if (api.equalsIgnoreCase("DEPLOYMENT")) {
baseURL = Environments.getDeploymentAPI();
}
final String finalBaseURL = baseURL;
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.build();
AndroidNetworking.initialize(context, okHttpClient);
AndroidNetworking.post(finalBaseURL + endpoint)
.setPriority(Priority.HIGH)
.addJSONObjectBody(body)
.addHeaders("Project", base64Header)
.addHeaders("Content-Type", "application/json")
.build()
.getAsJSONObject(new JSONObjectRequestListener() {
#Override
public void onResponse(JSONObject response) {
result[0] = String.valueOf(response);
}
#Override
public void onError(ANError anError) {
if (anError.getErrorCode() != 0) {
result[0] = String.valueOf(anError.getErrorDetail());
} else {
result[0] = String.valueOf(anError.getErrorDetail());
}
}
});
Log.i("data", result[0]);
}
}).start();
return result[0];
}
and calling the function on my App via :
String data = ActivationResponseV2.getActivationData(getContext(), "LOCAL", header, "/sample/response", jsonObject);
may I know what I'm doing wrong?. Thanks!
Response was returned outside the post call: To handle this you can pass a callback method to your function to consume the result when its ready.
public static void getActivationData(final Context context,
final String api, final String base64Header, final String endpoint,
final JSONObject body, Callable<Void> methodParam) {
String baseURL = null;
if (api.equalsIgnoreCase("LOCAL")) {
baseURL = Environments.getMarkLocalAPI();
} else if (api.equalsIgnoreCase("DEVELOPMENT")) {
baseURL = Environments.getDevelopmentAPI();
} else if (api.equalsIgnoreCase("STAGING")) {
baseURL = Environments.getStagingAPI();
} else if (api.equalsIgnoreCase("DEPLOYMENT")) {
baseURL = Environments.getDeploymentAPI();
}
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.build();
AndroidNetworking.initialize(context, okHttpClient);
AndroidNetworking.post(baseURL + endpoint)
.setPriority(Priority.HIGH)
.addJSONObjectBody(body)
.addHeaders("Project", base64Header)
.addHeaders("Content-Type", "application/json")
.build()
.getAsJSONObject(new JSONObjectRequestListener() {
#Override
public void onResponse(JSONObject response) {
//result[0] = String.valueOf(response);
methodParam.call(String.valueOf(response));
}
#Override
public void onError(ANError anError) {
if (anError.getErrorCode() != 0) {
// result[0] = String.valueOf(anError.getErrorDetail());
} else {
//result[0] = String.valueOf(anError.getErrorDetail());
}
methodParam.call(String.valueOf(anError.getErrorDetail()));
}
});
// Log.i("data", result[0]);
}
Use like below
ActivationResponseV2.getActivationData(getContext(), "LOCAL", header,
"/sample/response", jsonObject, new Callable<Void>() {
public Void call(String data) {
//...Consume data here
return null;
});
I have done it by using ANRequest. After reading this document. I tried to replicate it and I get my desired output.
This is the code :
public static synchronized String getActivationData(final Context context, final String api, final String base64Header, final String endpoint, final JSONObject body) {
final String[] result = {null};
String baseURL = null;
if (api.equalsIgnoreCase("LOCAL")) {
baseURL = Environments.getMarkLocalAPI();
} else if (api.equalsIgnoreCase("DEVELOPMENT")) {
baseURL = Environments.getDevelopmentAPI();
} else if (api.equalsIgnoreCase("STAGING")) {
baseURL = Environments.getStagingAPI();
} else if (api.equalsIgnoreCase("DEPLOYMENT")) {
baseURL = Environments.getDeploymentAPI();
}
final String finalBaseURL = baseURL;
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.build();
AndroidNetworking.initialize(context, okHttpClient);
ANRequest request = AndroidNetworking.post(finalBaseURL + endpoint)
.setPriority(Priority.HIGH)
.addJSONObjectBody(body)
.addHeaders("Project", base64Header)
.addHeaders("Content-Type", "application/json")
.build();
ANResponse response = request.executeForJSONObject();
if (response.isSuccess()) {
result[0] = String.valueOf(response.getResult());
Log.d(TAG, "response : " + result[0]);
} else {
ANError error = response.getError();
Log.d(TAG, "response : " + error);
}
return result[0];
}
}
Happy Coding!
I am trying to implement sendOTP of MSG91.There I have to API ,one for generating otp and another one for verifying otp.But there in post reuest I have to set a header ,so how can I set header in retrofit.I am attaching a pic of what to do.Please help me.enter image description here
post request:-
public class GenerateOTPRequest {
String countryCode;
String mobileNumber;
public GenerateOTPRequest(String countryCode, String mobileNumber) {
this.countryCode = countryCode;
this.mobileNumber = mobileNumber;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getMobileNumber() {
return mobileNumber;
}
public void setMobileNumber(String mobileNumber) {
this.mobileNumber = mobileNumber;
}
}
Response:-
public class GenerateOTPResponse {
#SerializedName("status")
#Expose
String status;
#SerializedName("response")
#Expose
String response;
public GenerateOTPResponse(String status, String response) {
this.status = status;
this.response = response;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
}
my main activity:-
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_verify_otp);
CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
.setDefaultFontPath("fonts/opensanslight.ttf")
.setFontAttrId(R.attr.fontPath)
.build()
);
getSupportActionBar().setTitle("Verify Your OTP");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
enterOTP = (EditText) findViewById(R.id.enter_otp);
verifyOTP = (Button) findViewById(R.id.verify_otp);
didntReceiveOTP = (TextView) findViewById(R.id.verify_otp_didnt_receive_otp);
sharedpreferences = getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE);
phone = sharedpreferences.getString(Phone, "notPresent");
Log.d("jkhdds: ", "" + phone);
GenerateOTPRequest generateOTPRequest = new GenerateOTPRequest("","");
generateOTPRequest.setCountryCode("91");
generateOTPRequest.setMobileNumber(phone);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("application-key", "oEBg-3z4hgcv5X8sk_AYdVDiqpGCN02G3cFRjCK0er6MWhuSHAQDRT3TuJKxzOI__2H3D_gZZWeMJsns92zEm4LlksdilXYePbiFZRc1OLZxZd1DmSQOlmM-MIhDrXOqefgIVJX_deqP0QfRoBZ-PtlqpCtZFRqem1kl_J2Vra8=")
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
Retrofit retrofit1 = new Retrofit.Builder()
.baseUrl("https://sendotp.msg91.com/api/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
final API service1 = retrofit1.create(API.class);
Call<GenerateOTPResponse> call = service1.generateOTP(generateOTPRequest);
call.enqueue(new Callback<GenerateOTPResponse>() {
#Override
public void onResponse(Call<GenerateOTPResponse> call, retrofit2.Response<GenerateOTPResponse> response) {
//GenerateOTPResponse generateOTPResponse = response.body();
//String status = otpResponse.getStatus();
Log.d("otp response " , response.body().getResponse());
}
#Override
public void onFailure(Call<GenerateOTPResponse> call, Throwable t) {
}
});
Log.d("Tag", String.valueOf(enterOTP.getText()));
OkHttpClient.Builder httpClient1 = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("application-key", "oEBg-3z4hgcv5X8sk_AYdVDiqpGCN02G3cFRjCK0er6MWhuSHAQDRT3TuJKxzOI__2H3D_gZZWeMJsns92zEm4LlksdilXYePbiFZRc1OLZxZd1DmSQOlmM-MIhDrXOqefgIVJX_deqP0QfRoBZ-PtlqpCtZFRqem1kl_J2Vra8=")
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
});
OkHttpClient client1 = httpClient1.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://sendotp.msg91.com/api/")
.addConverterFactory(GsonConverterFactory.create())
.client(client1)
.build();
final API service = retrofit.create(API.class);
Log.d("Tag",enterOTP.getText().toString());
Log.d("Tag","fuck u");
verifyOTP.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final VerifyOTPRequest verifyOTPRequest = new VerifyOTPRequest("","","");
verifyOTPRequest.setCountryCode("91");
verifyOTPRequest.setMobileNumber(phone);
verifyOTPRequest.setOneTimePassword(enterOTP.getText().toString());
Log.d("Tag",enterOTP.getText().toString());
Call<VerifyOTPResponse> call = service.verifyOTP(verifyOTPRequest);
call.enqueue(new Callback<VerifyOTPResponse>() {
#Override
public void onResponse(Call<VerifyOTPResponse> call, retrofit2.Response<VerifyOTPResponse> response) {
Log.d("Tag", String.valueOf(response.body()));
String message = response.body().getStatus();
Log.d("Tag",message);
if (message.equals("success")) {
Toast.makeText(getApplicationContext(), "Successfully Verified", Toast.LENGTH_LONG).show();
Intent intent1 = getIntent();
String parentActivityName = intent1.getStringExtra("activity");
if (parentActivityName.equals("signup")) {
Intent selectSubject = new Intent(VerifyOTPActivity.this, SelectSubjectActivity.class);
progressDialog.dismiss();
startActivity(selectSubject);
} else {
Intent changepassword = new Intent(VerifyOTPActivity.this, ChangePasswordActivity.class);
progressDialog.dismiss();
startActivity(changepassword);
}
}
Log.d("message csdkhds", "" + message);
Log.d("phonre : ", " " + phone);
}
#Override
public void onFailure(Call<VerifyOTPResponse> call, Throwable t) {
}
});
}
});
}
my interface:-
#POST("generateOTP")
Call<GenerateOTPResponse> generateOTP(#Body GenerateOTPRequest generateOTPRequest);
#POST("verifyOTP")
Call<VerifyOTPResponse> verifyOTP(#Body VerifyOTPRequest verifyOTPRequest);
Just use annotation:
public interface Service {
#Headers("application-Key", your key)
#GET("/example")
Call<List<Example>> getExamples();
}
All examples are available here: https://futurestud.io/tutorials/retrofit-add-custom-request-header
You can use #Header annotation for your api method as it is clearly stated in a documentation https://square.github.io/retrofit/
#Headers("XYZ: value")
you can set it in your base retrofit file
request = original.newBuilder()
.header("header key", "your header)
.header("x-requested-with", "XMLHttpRequest")
.method(original.method(), original.body())
.build();
okhttp3.Response response = chain.proceed(request);
#Header
this is a Retrofit specific annotation which will allow you the pass the request headers to the targeting HTTP endpoint, where every argument represents a request header entry.
I am trying to add basic authentication (username and password) to a Retrofit OkHttp client. This is the code I have so far:
private static Retrofit createMMSATService(String baseUrl, String user, String pass) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
I am using Retrofit 2.2 and this tutorial suggests using AuthenticationInterceptor, but this class is not available.
Where is the correct place to add the credentials? Do I have to add them to my interceptor, client or Retrofit object? And how do I do that?
Find the Solution
1.Write a Interceptor class
import java.io.IOException;
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class BasicAuthInterceptor implements Interceptor {
private String credentials;
public BasicAuthInterceptor(String user, String password) {
this.credentials = Credentials.basic(user, password);
}
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request authenticatedRequest = request.newBuilder()
.header("Authorization", credentials).build();
return chain.proceed(authenticatedRequest);
}
}
2.Finally, add the interceptor to an OkHttp client
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new BasicAuthInterceptor(username, password))
.build();
Retrofit 2
public class ServiceGenerator {
public static final String API_BASE_URL = "https://your.api-base.url";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
private static Retrofit retrofit = builder.build();
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null, null);
}
public static <S> S createService(
Class<S> serviceClass, String username, String password) {
if (!TextUtils.isEmpty(username)
&& !TextUtils.isEmpty(password)) {
String authToken = Credentials.basic(username, password);
return createService(serviceClass, authToken);
}
return createService(serviceClass, null);
}
public static <S> S createService(
Class<S> serviceClass, final String authToken) {
if (!TextUtils.isEmpty(authToken)) {
AuthenticationInterceptor interceptor =
new AuthenticationInterceptor(authToken);
if (!httpClient.interceptors().contains(interceptor)) {
httpClient.addInterceptor(interceptor);
builder.client(httpClient.build());
retrofit = builder.build();
}
}
return retrofit.create(serviceClass);
}
}
Retrofit 1.9
public class ServiceGenerator {
public static final String API_BASE_URL = "https://your.api-base.url";
private static RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(API_BASE_URL)
.setClient(new OkClient(new OkHttpClient()));
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null, null);
}
public static <S> S createService(Class<S> serviceClass, String username, String password) {
if (username != null && password != null) {
// concatenate username and password with colon for authentication
String credentials = username + ":" + password;
// create Base64 encodet string
final String basic =
"Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
builder.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader("Authorization", basic);
request.addHeader("Accept", "application/json");
}
});
}
RestAdapter adapter = builder.build();
return adapter.create(serviceClass);
}
}
AuthenticationInterceptor.java
public class AuthenticationInterceptor implements Interceptor {
private String authToken;
public AuthenticationInterceptor(String token) {
this.authToken = token;
}
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder builder = original.newBuilder()
.header("Authorization", authToken);
Request request = builder.build();
return chain.proceed(request);
}
}
Usage
Retrofit 2
Interface
public interface LoginService {
#POST("/login")
Call<User> basicLogin();
}
Requester
LoginService loginService =
ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
Call<User> call = loginService.basicLogin();
call.enqueue(new Callback<User >() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
// user object available
} else {
// error response, no access to resource?
}
}
#Override
public void onFailure(Call<User> call, Throwable t) {
// something went completely south (like no internet connection)
Log.d("Error", t.getMessage());
}
}
Retrofit 1.9
Interface
public interface LoginService {
#POST("/login")
void basicLogin(Callback<User> cb);
}
Requester
LoginService loginService =
ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
loginService.basicLogin(new Callback<User>() {
#Override
public void success(User user, Response response) {
// user object available
}
#Override
public void failure(RetrofitError error) {
// handle errors, too
}
});
More information see here.
add header interceptor
public class HeaderInterceptor implements Interceptor {
private PreferencesRepository mPrefs;
private String mAuth;
public HeaderInterceptor(PreferencesRepository p) {
mPrefs = p;
}
#Override
public Response intercept(Chain chain) throws IOException {
mAuth = (mPrefs.getAuthToken() != null)?mPrefs.getAuthToken():"";
Request r = chain.request()
.newBuilder()
.addHeader("Accept", "application/json")
// authorization token here
.addHeader("Authorization", "Bearer" + mAuth)
.build();
return chain.proceed(r);
}
}
add cacheinterceptor (optional)
public class CacheInterceptor implements Interceptor {
Context mContext;
public CacheInterceptor(Context context) {
this.mContext = context;
}
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (request.method().equals("GET")) {
if (DeviceUtils.isConnected(mContext)) {
request = request.newBuilder()
.header(Constant.CACHE_CONTROL, "only-if-cached")
.build();
} else {
request = request.newBuilder()
.header(Constant.CACHE_CONTROL, "public, max-stale=2419200")
.build();
}
}
Response originalResponse = chain.proceed(request);
return originalResponse.newBuilder()
.header(Constant.CACHE_CONTROL, "max-age=600")
.build();
}
}
implement it
HttpLoggingInterceptor logger = new HttpLoggingInterceptor();
logger.setLevel(HttpLoggingInterceptor.Level.BODY);
long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(new File(mContext.getCacheDir(), "http"), SIZE_OF_CACHE);
new OkHttpClient.Builder()
.addInterceptor(logger)
.addInterceptor(new HeaderInterceptor(u))
.cache(cache)
.addNetworkInterceptor(new CacheInterceptor(mContext))
.connectTimeout(Constant.CONNECTTIMEOUT, TimeUnit.SECONDS)
.readTimeout(Constant.READTIMEOUT, TimeUnit.SECONDS)
.writeTimeout(Constant.WRITETIMEOUT, TimeUnit.SECONDS)
.build();
Of course using auth interceptor is correct way (as explained in other answers). Although, if you need basic authentication only for single call, then auth header can be added directly in Retrofit request:
import okhttp3.Credentials
// Create credentials
val login = "some login"
val password = "some password"
// Below code will create correct Base64 encoded Basic Auth credentials
val credentials = Credentials.basic(login, password)
// Then in your Retrofit API interface
interface MyApi {
#POST("get_user")
fun getUser(#Header("Authorization") credentials: String): ResponseBody
}
Callback is not working on some screens sometimes while many times it's working perfectly. I have almost done project with this library. So kindly help
My ApiClient code is:
public class ApiClient {
public static final String BASE_URL = AppUtils.MainURL;
private static Retrofit retrofit = null;
public static Retrofit getClient(final String token) {
OkHttpClient defaultHttpClient = new OkHttpClient.Builder()
.addInterceptor(
new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("AccessToken", token).build();
return chain.proceed(request);
}
}).retryOnConnectionFailure(true).connectTimeout(1, TimeUnit.MINUTES)
.readTimeout(1, TimeUnit.MINUTES)
.writeTimeout(1, TimeUnit.MINUTES).build();
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(defaultHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
and calling method is:
ApiInfo apiService =
ApiClient.getClient(preference.getToken()).create(ApiInfo.class);
Call<JobDetailsResponse> responseCall = apiService.getJobDetails(preference.getLoginId(), preference.getToken(), "" + jobId);
responseCall.enqueue(new Callback<JobDetailsResponse>() {
#Override
public void onResponse(Call<JobDetailsResponse> call, Response<JobDetailsResponse> response) {
progressDialog.dismiss();
JobDetailsResponse jobDetailsResponse = response.body();
}
#Override
public void onFailure(Call<JobDetailsResponse> call, Throwable t) {
progressDialog.dismiss();
}
});