I have an old app which uses raw okhttp calls and utilizes sessions.
OkHttp is setup by this code:
OkHttpClient okHttpClient = null;
try {
OkHttpClient.Builder builder = SupportRequests.getUnsafeOkHttpClient();
builder.readTimeout(5000, TimeUnit.MILLISECONDS);
builder.connectTimeout(10000, TimeUnit.MILLISECONDS);
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
builder.cookieJar(new JavaNetCookieJar(cookieManager));
okHttpClient = builder.build();
SupportRequests.setOkHttpClient(okHttpClient);
} catch (NoSuchAlgorithmException | KeyManagementException e) {
FirebaseCrash.report(e);
}
I want to switch to using retrofit. The app is quite big and contains several dozens requests. Making it in a one-time switch is not possible.
I tried to start switching and encountered a problem.
Retrofit and okHtpp raw calls do not share PHP session.
I create retrofit with following code:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Preferences.getInstance().server)
.addConverterFactory(GsonConverterFactory.create(SupportGson.get()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.build();
retrofitProvider.setRetrofit(retrofit);
But sessions are different for retrofit calls and raw okhttp calls.
Any idea how to make them share session?
Related
I using Retrofit to making API call. All API call is working fine except one where its returning huge response around 15k records.
Issue is when made call progress bar is being shown infinitely until I get response. And as response too huge getting OOM exception.
As an solution I found that need to use #Streaming annotation. I used that but didn't get intermediate callback. I want API should return chunk of response one by one.
Please help me.
public static ServiceInterface getServiceAPIClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
Gson gson = new GsonBuilder()
.setLenient()
.create();
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(
new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
Request.Builder builder = request.newBuilder();
builder = request.newBuilder();
if (!TextUtils.isEmpty(PrefsHelper.getAccessTokenEdrm())) {
builder.addHeader(AUTHORIZATION, PrefsHelper.getAccessTokenEdrm());
}
builder.addHeader(API_VERSION, "1.0")
.addHeader("Accept", "application/json");
request = builder.build();
return chain.proceed(request);
}
}).connectTimeout(5, TimeUnit.MINUTES) .readTimeout(5, TimeUnit.MINUTES).addInterceptor(interceptor)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build();
return retrofit.create(ServiceInterface.class);
}
API Method
#POST(EdrmConstants.SEARCH_DOCUMENTS)
#Streaming
Observable<ResponseBody> searchDocuments(#Body DocumentRequest documentRequest);
15k records is too match.
Retrofit needs time to make http request and makes serialization to your ResponseBody.class
I sure serialization takes main time.
I guess most right solution is to edit request on server side to split data on pages with 200-500 records.
I've been reading about Retrofit and I got to the point of Headers and I don't know if I understood them too well. In the course I'm doing it uses them to establish an authentication with a user created in the backend and a database and it does it in two different ways:
private WebServiceBA() {
loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.level(HttpLoggingInterceptor.Level.BODY);
httpClientBuilder = new OkHttpClient.Builder().addInterceptor(loggingInterceptor);
httpClientBuilder.addInterceptor(chain -> {
Request original = chain.request();
Request.Builder requestBuild = original
.newBuilder()
.addHeader("Authorization", AUTH_USER)
.method(original.method(), original.body());
Request request = requestBuild.build();
return chain.proceed(request);
});
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL_BA)
.client(httpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
}
In this first form I understand that the Header is passing through code but I don't understand the .method(original.method(), original.body());. And in this one it's passing it through the Retrofit call itself:
#GET("/todos_profesores_admin")
Call<List<ProfesorBA>> listAllProfesorAdmin(#Header("Authorization") String authHeader);
I don't understand if "Authorization" is something that should be like that since it's in the backend or it's a way to call it in the code.
I suppose that by doing it in the call, in this case we have more freedom since we pass him the users that we want, but what other things can we send through the Header of a Retrofit call or how far does its usefulness extend? Thank you very much.
I have an android app already uploaded to store and working fine, sometimes when a lot of users open the app at the same time (eg. when sending a notification) our servers are getting overloaded and stops responding for about 10 to 15 minutes. I'm using Retrofit 2 to send requests to our server from the app, I've checked all the app requests there are no places where the request is happening when it shouldn't or needed, finally, I added a logging interceptor to retrofit to track the requests and I was surprised that each request is being called more than ten times for no apparent reason! as you can see in the following image:
This is happening with all requests called from the app for no apparent reason. My service generator for Retrofit 2 is the following:
private static OkHttpClient.Builder httpClient
= new OkHttpClient.Builder().connectTimeout(10000, TimeUnit.SECONDS)
.readTimeout(10000, TimeUnit.SECONDS).addInterceptor(new FakeInterceptor())
.addNetworkInterceptor(new StethoInterceptor())
.retryOnConnectionFailure(false);
private static Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, new DateDeserializer())
.create();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL));
public static <S> S createService(Class<S> serviceClass) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
httpClient.addInterceptor(logging);
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
I am sure request is only called once from my code but I have no idea why Retrofit is making all these useless and unnecessary requests. What might be the problem? Thanks in advance, any help is much appreciated.
It's because you are creating multiple instances of the Retrofit client. You should declare a static instance of Retrofit in your class and change
Retrofit retrofit = builder.client(httpClient.build()).build();
to
if(retrofit == null) {
retrofit = builder.client(httpClient.build()).build();
}
Reference: https://github.com/square/retrofit/issues/1724
I am using retrofit with Rxjava to get response from API as you can see the method i am using i can't see what's coming in the response and offcourse i don't need to becuase i am providing GsonConverter to retrofit but for some debugging reason i need to see the response that coming from API. How can i do this, what code i need to add.
public interface ProductApiService
{
String END_POINT = "http://beta.site.com/index.php/restmob/";
#GET(Url.URL_PRODUCT_API)
Observable<Product> getProducts(#Query("some_id") String cid);
class Creator
{
public static ProductApiService getProductAPIService() {
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ProductApiService.END_POINT)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
return retrofit.create(ProductApiService.class);
}
}
}
You can only do this as of Retrofit 2: Change the return type to include Response:
#GET(Url.URL_PRODUCT_API)
Observable<Response<Product>> getProducts(/* ...etc... */);
You can also use Observable<Result<Product>> if you want to see all possible errors in onNext (including IOException, which normally uses onError).
Daniel Lew's approach is quick and contains the least amount of boiler plate code. However, this may force you to refactor your networking logic. Since you mention needing this for debugging purposes, perhaps using a configured OkHttpClient with Interceptors is a less intrusive strategy.
OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request req = chain.request();
Response resp = chain.proceed(req);
// ... do something with response
return resp;
}
})
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(httpClient)
.baseUrl(ProductApiService.END_POINT)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
I have searched for this but didn't got any appropriate ans. I am developing a social android app in which some feed data need to cache show that when user open this app and there is no network connection won't get blank screen. what is the best and fast access way to cache web data.
You will most likely parse the HTTP data into your own objects. So the question will rather be how to serialize these objects, and save them. These are the most common formats for object serialization:
a plain file, such as in XML or JSON format
a SQLite database
SharedPreferences (as a Set, so this will only work well if the order of the strings is able to be rebuilt later, such as them being in alphabetical order)
(These points look common, eh, #CommonsWare ;)
Facebook, for example, uses an SQLite database, at least for their iOS app.
If you are using retrofit then you can use cache interceptors.
Firstly declare cache memory size
int cacheSize = 10 * 1024 * 1024; // this is 10MB
Then create a cache object
Cache provideCache(MyApplication context) {
Cache cache = null;
try {
cache = new Cache(new File(context.getCacheDir(), "http-cache"), cacheSize);
} catch (Exception e) {
Log.e("Cache", "Error in creating Cache!");
}
return cache;
}
Then create 2 network interceptors for HTTP client ( One for Online, one for No network case)
Interceptor provideOnlineInterceptor(MyApplication context) {
return chain -> {
Response response = chain.proceed(chain.request());
CacheControl cacheControl;
if (Utilities.isNetworkConnected(context)) {
cacheControl = new CacheControl.Builder().maxAge(0, TimeUnit.SECONDS).build();
} else {
cacheControl = new CacheControl.Builder()
.maxStale(7, TimeUnit.DAYS)
.build();
}
return response.newBuilder()
.removeHeader(HEADER_PRAGMA)
.removeHeader(HEADER_CACHE_CONTROL)
.header(HEADER_CACHE_CONTROL, cacheControl.toString())
.build();
};
Interceptor provideOfflineInterceptor(MyApplication context) {
return chain -> {
Request request = chain.request();
if (!Utilities.isNetworkConnected(context)) {
CacheControl cacheControl = new CacheControl.Builder()
.maxStale(7, TimeUnit.DAYS)
.build();
request = request.newBuilder()
.removeHeader(HEADER_PRAGMA)
.removeHeader(HEADER_CACHE_CONTROL)
.cacheControl(cacheControl)
.build();
}
return chain.proceed(request);
};
Create Httpclient
OkHttpClient provideOkHttpClient(MyApplication context) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.addInterceptor(provideOfflineCacheInterceptor(context))
.addNetworkInterceptor(provideCacheInterceptor(context))
.cache(provideCache(context));
return httpClient.build();
}
Then finally add this httpclient to Retrofit instance
Retrofit provideRetrofit(OkHttpClient client,Gson gson) {
return new Retrofit.Builder().baseUrl(ApiConstants.BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build();
}
Hope this will work.
Please go through below link for more detail
Network caching using interceptors