一.概述
在众多的网络请求中,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/";