一.概述
在众多的网络请求中,okhttp算口碑很不错的,再加上和Retrofit的结合,那用起来简直就是太方便了。
- 关于Okhttp的知识点,可以参考:https://blog.piasy.com/2016/07/11/Understand-OkHttp/
- 关于Retrofit的知识点,可以参考:https://blog.csdn.net/u014695188/article/details/52985514
Retrofit的优势:
- 首先,Retrofit使用注解方式,大大简化了我们的URL拼写形式,而且注解含义一目了然,简单易懂;
- 其次,Retrofit使用简单,结构层次分明,每一步都能清晰的表达出之所以要使用的寓意;
- 再者,Retrofit支持同步和异步执行,使得请求变得异常简单,只要调用enqueue/execute即可完成;
- 最后,Retrofit更大自由度的支持我们自定义的业务逻辑,如自定义Converters。
导入依赖库:
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.okhttp3:okhttp:3.9.1'
compile 'com.squareup.okio:okio:1.13.0'
compile 'com.google.code.gson:gson:2.8.2'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:converter-scalars:2.3.0'
二.使用
1.接口服务包装类RetrofitWrapper.java,负责网络请求的相关配置:
public class RetrofitWrapper {
private static RetrofitWrapper instance;
private Retrofit retrofit;
private RetrofitWrapper() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
/**
*设置缓存
*/
final File chachefile = new File("CacheFilePath");
final Cache cache = new Cache(chachefile, 1024 * 1024 * 50);//缓存文件
Interceptor cacheInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!AppUtils.isNetworkReachable(AppAplication.getContext())) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (AppUtils.isNetworkReachable(AppAplication.getContext())) {
int maxAge = 0;
// 有网络时 设置缓存超时时间0个小时
response.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader("Pragma")// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
.build();
} else {
//无网络时,设置超时为4周
int maxStale = 60 * 60 * 24 * 28;
response.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader("Pragma")
.build();
}
return response;
}
};
builder.cache(cache).addInterceptor(cacheInterceptor);
/**
*公共参数
*/
Interceptor addQueryParameterInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Request request;
String method = originalRequest.method();
Headers headers = originalRequest.headers();
HttpUrl modifiedUrl = originalRequest.url().newBuilder()
// Provide your custom parameter here
.addQueryParameter("platform", "adnroid")
.addQueryParameter("version", "1.2.0")
.build();
request = originalRequest.newBuilder().url(modifiedUrl).build();
return chain.proceed(request);
}
};
builder.addInterceptor(addQueryParameterInterceptor);
/**
* 设置请求头
*/
Interceptor headerInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request orignaRequest = chain.request();
Request request = orignaRequest.newBuilder()
.header("AppType", "TPOS")
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.method(orignaRequest.method(), orignaRequest.body())
.build();
return chain.proceed(request);
}
};
builder.addInterceptor(headerInterceptor);
/**
* Log信息拦截器
*/
//compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
if (BuildConfig.DEBUG) {
//log信息拦截器
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//设置Debug Log模式
builder.addInterceptor(httpLoggingInterceptor);
}
/**
* 设置cookie
*/
//compile 'com.squareup.okhttp3:okhttp-urlconnection:3.4.1'
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
builder.cookieJar(new JavaNetCookieJar(cookieManager));
/**
* 设置超时和重连
*/
//设置超时
builder.connectTimeout(15, TimeUnit.SECONDS);
builder.readTimeout(20, TimeUnit.SECONDS);
builder.writeTimeout(20, TimeUnit.SECONDS);
//错误重连
builder.retryOnConnectionFailure(true);
//以上设置结束,才能build(),不然设置白搭 (上面的设置都可以省略)
OkHttpClient okHttpClient = builder.build();
retrofit = new Retrofit.Builder()
.baseUrl(ApiUtils.BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create()) // 解析方法
.client(okHttpClient)
.build();
}
/**
* 单例模式
*
* @return
*/
public static RetrofitWrapper getInstance() {
if (instance == null) {
synchronized (RetrofitWrapper.class) {
if (instance == null) {
instance = new RetrofitWrapper();
}
}
}
return instance;
}
public <T> T create(final Class<T> service) {
return retrofit.create(service);
}
}
其中:设置缓存、公共参数、设置请求头、Log信息拦截器、设置cookie、设置超时和重连如果不需要都可以省略
2.接口调用类RetrofitModel.java,负责具体调用的接口
/**
* 接口调用类
* @author WangBin
* @date 2018年1月15日 下午5:29:56
* @Description: TODO
* @version V1.0
*/
public class RetrofitModel {
private static RetrofitModel retrofitModel;
private RetrofitService retrofitService;
public static RetrofitModel getInstance() {
if (retrofitModel == null) {
retrofitModel = new RetrofitModel();
}
return retrofitModel;
}
private RetrofitModel() {
retrofitService = RetrofitWrapper.getInstance().create(RetrofitService.class);
}
/**
* 获取用户信息(异步)
* @param username
* @param callback
*/
public void getUser(String username, HttpCallback<User> callback) {
Call<User> call = retrofitService.getUser(username);
RetrofitRequest<User> request = new RetrofitRequest<User>(call);
request.requestAsync(callback);
}
/**
* 获取用户信息(同步)
* @param username
* @return
*/
public User getUserSync(String username){
Call<User> call = retrofitService.getUser(username);
RetrofitRequest<User> request = new RetrofitRequest<User>(call);
return request.requestSync();
}
}
3.接口api类RetrofitService.java
public interface RetrofitService {
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
@POST("android/login.in")
Call<String> login(@Query("loginName") String loginName, @Query("password") String password);
/**
@Path:所有在网址中的参数(URL的问号前面),如:
http://102.10.10.132/api/Accounts/{accountId}
@Query:URL问号后面的参数,如:
http://102.10.10.132/api/Comments?access_token={access_token}
@QueryMap:相当于多个@Query
@Field:用于POST请求,提交单个数据
@Body:相当于多个@Field,以对象的形式提交
**/
}
4.具体的网络请求类RetrofitRequest.java
public class RetrofitRequest<T> {
private Call<T> mCall;
public RetrofitRequest(Call<T> call) {
mCall = call;
}
/**
* 异步请求
*
* @param callback
*/
public void requestAsync(final HttpCallback<T> callback) {
mCall.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
String path = mCall.request().url().toString();
if (response.isSuccessful() && response.errorBody() == null) {
callback.onSuccess((T) response.body(), path);
} else {
callback.onFailure(response.errorBody().toString());
}
}
@Override
public void onFailure(Call<T> call, Throwable t) {
callback.onFailure(t.getMessage());
}
});
}
/**
* 同步请求
*
* @return
*/
public T requestSync() {
Response<T> response = null;
try {
response = mCall.execute();
} catch (IOException e) {
e.printStackTrace();
}
return (T) response.body();
}
5.请求回调类HttpCallback.java
public abstract class HttpCallback<T> {
public Class<?> clazz;
public HttpCallback() {
Type superclass = getClass().getGenericSuperclass();
ParameterizedType parameterizedType = null;
if (superclass instanceof ParameterizedType) {// 参数化的泛型
parameterizedType = (ParameterizedType) superclass;
Type[] typeArray = parameterizedType.getActualTypeArguments();
if (typeArray != null && typeArray.length > 0) {
clazz = (Class<?>) typeArray[0];
}
}
}
public abstract void onSuccess(T response, String path);
public abstract void onFailure(String errorResponse);
}
示例中使用到的Apiutils.BASE_URL为:public static final String BASE_URL = "https://api.github.com/";