有人可以帮我理解下面代码中的createService
方法。我需要了解方法的参数类S
以及深度下的代码
public class ServiceGenerator {
public static final String API_BASE_URL = Constant.BASE_URL;
private static OkHttpClient httpClient = new OkHttpClient();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
httpClient.interceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("cache-control","no-cache")
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
Retrofit retrofit = builder.client(httpClient).build();
return retrofit.create(serviceClass);
}
}
答案 0 :(得分:8)
自己找到答案。整个createservice
方法在此代码中并非绝对必要,并且可以在没有interceptor
声明的情况下生效,如下所示。如果有人想为httpClient
等cache-control, authorization token
设置拦截器方法,可以使用完整的代码块来设置它们。最简单的createService版本是
public class ServiceGenerator {
public static <S> S createService(Class<S> serviceClass) {
Retrofit retrofit = builder.client(httpClient).build();
return retrofit.create(serviceClass);
}
}
这里“S”是类类型参数。它用于指定输出类型类与输入类相同。然后,您可以在任何activity / fragment
中使用此代码创建自己的api接口MyApiService myapiservice = ServiceGenerator.createService(MyApiServiceInterface.class)
Call<YourDataResponseClass> call = myapiService.getMyData(YourDataRequestClass);
call.enqueue ({.....remaining code})
将MyApiService
定义如下
public interface MyApiServiceInterface {
/*Base url is already defined in service generator class*/
@GET("/your/api/endpoint/")
/*YourDataResponseClass and YourDataRequestClass are
pojo object notation of your request and response json*/
YouDataResponseClass getMyData(
@Body YourDataRequestClass request
);
}
答案 1 :(得分:3)
我遇到了同样的问题。几分钟后研究发生了什么我意识到了这个问题。基本上你不必使用这行代码:
private static OkHttpClient httpClient = new OkHttpClient();
这是问题所在,每次都使用类似的静态变量:
Retrofit retrofit = builder.client(httpClient).build();
您正在创建该对象的另一个相同实例,而旧版本正在使用相同的引用并添加N个拦截器对象,并且每个拦截器对象都是Rest客户端(请注意这一点,&lt; ----主要问题。因此,您必须检查HttpClient是否已经制作完成。因此,解决此问题的最终解决方案是下一个:
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.fastjson.FastJsonConverterFactory;
import utils.Constantes;
/**
* Created by abeld on 19/05/2016.
*/
public class ServiceGenerator {
public static final String API_BASE_URL = Constantes.URL_SERVER;
private static OkHttpClient.Builder httpClient;
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(FastJsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null);
}
public static <S> S createService(Class<S> serviceClass, final AccessToken token) {
if(httpClient == null){
httpClient = new OkHttpClient.Builder();
if (token != null) {
httpClient.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("Accept", "application/json")
.header("Authorization", token.getTypeTokenAndToken())
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
}
httpClient.connectTimeout(50, TimeUnit.SECONDS);
httpClient.addInterceptor(addLoggin());
}
OkHttpClient client = httpClient.build();
Retrofit retrofit = builder.client(client).build();
return retrofit.create(serviceClass);
}
private static HttpLoggingInterceptor addLoggin(){
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
return logging;
}
}
正如您所看到的,我检查对象是否已经为空,在这种情况下只需在其他情况下创建一个实例跳过。
顺便说一下,如果你使用像记录器一样添加一个新的拦截器,你可以在你的Android Studio控制台中看到你所做的请愿数量,如果请愿数量只有1,你就修复了缺陷。
答案 2 :(得分:2)
我决定发布一个优化版本,该版本将添加必要的Interceptors
(如授权Interceptors
)。
此版本很不错,因为它不会重新创建/构建任何或必需的ApiClient对象(OkHttpClient
,Retrofit.Builder
,Retrofit
)。从而节省了处理时间和内存。
public class ApiClient
{
public static final String BASE_URL = "https://my.auth.url/";
// The singleton HTTP client (do initial customizations here).
// We can add more customizations later by using the client.newBuilder() method, which will essentially clone this instance (more efficient to do that).
private static OkHttpClient client = new OkHttpClient().newBuilder()
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS).build();
// You want to make this static and initialize because once again,
// we can custom later on the fly.
private static Retrofit.Builder adapterBuilder = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonCustomConverterFactory.
create(new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
.create()));
// Important to build when declaring the Retrofit object,
// for optimization purposes (so you don’t have to rebuild it every time).
private static Retrofit retrofit = adapterBuilder.build();
public static <S> S createService(Class<S> serviceClass)
{
return retrofit.create(serviceClass);
}
public static <S> S createService(Class<S> serviceClass, final String authTokenString)
{
if (!TextUtils.isEmpty(authTokenString))
{
AuthenticationInterceptor authenticationInterceptor =
new AuthenticationInterceptor(authTokenString);
/*
Check if the AuthenticationInterceptor has already been applied;
*/
if (!client.interceptors().contains(authenticationInterceptor))
{
/*
Clone the client and set the AuthenticationInterceptor, build, and then
set this to be our new client, because we want this in every request.
*/
client = client.newBuilder().addInterceptor(authenticationInterceptor).build();
// Clone the Retrofit builder and set it to be our new Retrofit.Builder.
adapterBuilder = retrofit.newBuilder();
/*
Add our client to the Retrofit.Builder, then build the new Retrofit instance
We have now set up ApiClient to add the Authorization to every request.
*/
retrofit = adapterBuilder.client(client).build();
}
}
return retrofit.create(serviceClass);
}
public static <S> S createService(
Class<S> serviceClass, String username, String password)
{
if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password))
{
// Create the interceptor
HttpBasicAuth basicAuth = new HttpBasicAuth(username, password);
/* Here we clone our OkHttpClient that we built as a static class variable.
Notice we use:
"client.newBuilder()”, this clones the builder with everything we
initially set up, it’s very efficient, and actually how the OkHttp3
documentation suggests it be used.
*/
OkHttpClient basicClient = client.newBuilder().addInterceptor(basicAuth).build();
// We clone the Retrofit.Builder, add the client, build and create the service class, all very efficient.
// This only sets the “HttpBasicAuth” interceptor for this request since it should only be used once.
return retrofit.newBuilder()
.client(basicClient)
.build()
.create(serviceClass);
}
return retrofit.create(serviceClass);
}
}
以下是基本(用户名和密码)授权的HttpBasicAuth
类和Interceptor
,例如您需要首次授权用户,之后您将使用授权令牌
public class HttpBasicAuth implements Interceptor
{
private String username;
private String password;
public HttpBasicAuth(String username, String password)
{
this.username = username;
this.password = password;
}
@Override
public Response intercept(Chain chain) throws IOException
{
Request request = chain.request();
// If the request already have an authorization (eg. Basic auth), do nothing
if (request.header("Authorization") == null)
{
String credentials = Credentials.basic(username, password);
request = request.newBuilder()
.header("Authorization", credentials)
.header("Accept", "application/json")
.build();
}
return chain.proceed(request);
}
}
以下是用于令牌授权的AuthenticationInterceptor
类和Interceptor
,这将应用于每个请求。
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();
if (authToken != null && !authToken.isEmpty())
{
/*
Using ".header("Authorization", authToken)”, will overwrite
any old Authorization header values, which we want to do.
*/
original = original.newBuilder()
.header("Authorization", authToken).build();
}
return chain.proceed(original);
}
}
链接到有关如何有效使用OkHttpClient的文档。
答案 3 :(得分:0)
这是我的解决方案
import android.os.SystemClock;
import java.io.IOException;
import okhttp3.Dispatcher;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class GenericClient<T> {
public T getClient(Class<T> repoClass) {
// It add the retry logic
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequests(10);
// It add the delay logic
Interceptor networkInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
SystemClock.sleep(2000);
return chain.proceed(chain.request());
}
};
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(networkInterceptor)
.dispatcher(dispatcher)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Network.SERVER_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit.create(repoClass);
}
}
及其实现
AboutClient.getClient().about().enqueue(new Callback<AboutResponse>() {
@Override
public void onResponse(Call<AboutResponse> call, Response<AboutResponse> response) {
}
@Override
public void onFailure(Call<AboutResponse> call, Throwable t) {
}
});