关于Retrofit基础知识的学习,请参考这篇文章
代码的封装
1.APIService 使用Retrofit要求我们将项目中使用的接口请求定义写在一个接口中,咱们就写在APIService中。
2.RetrofitClient类,该类就是retrofit请求管理类,该类使用单例模式,封装了项目使用的Intercepter、baseUrl、connectTimeOut、convertFactory等,
private RetrofitClient() {
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
if (ColorVConst.DEBUG) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
okHttpClientBuilder.addInterceptor(logging);
}
okHttpClientBuilder.addInterceptor(new HeaderInterceptor())
.addInterceptor(new ResponseIntercepter())
.connectTimeout(DEFAULT_TIME_LIMIT, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClientBuilder.build())
.baseUrl(ServerInterfaceConst.BACK_SERVER)
.addConverterFactory(JsonConverterFactory.create())
.build();
apiService = retrofit.create(APIService.class);
}
public APIService getApiService() {
//通过该方法就能得到1中的ApIService对象
return apiService;
}
3.HeadIntercepter类,因为咱们每次请求都需要向服务器发送utk,所以统一发送Header比较方便,所以就在retrofit请求的时候进行拦截,将header加到请求中,自定义Intercepter需要实现Intercepter接口,并实现intercept方法。
public class HeaderInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request()
.newBuilder();
try {
Map<String, String> headers = ServerHandler.getCommonHeaders();
for (String key : headers.keySet()) {
builder.addHeader(key, headers.get(key));
}
} catch (JSONException e) {
e.printStackTrace();
}
return chain.proceed(builder.build());
}
}
4.ResponseIntercepter 因为咱们部分json返回的时候Content-Encoding格式为gzip,而retrofit好像没处理这种情况,所以需要对返回后的数据进行拦截并处理。
5.JsonConverterFactory 该类描述了在请求数据时和返回数据时序列化反序列化的规则,该类继承Converter.Factory,并需要实现两个方法
public class JsonConverterFactory extends Converter.Factory {
public static JsonConverterFactory create() {
return new JsonConverterFactory(new Gson());
}
private Gson gson;
private JsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
//表示返回的数据反序列化为Java Bean的规则
return new JsonResponseBodyConverter<>(type, gson, annotations);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
//表示请求的数据对象序列化为json的规则
return new JsonRequestBodyConverter<>(gson, adapter);
}
}
5.JsonRequestBodyConverter 表示post请求的数据对象序列化为json的规则 里面实现使用gson序列化,如果实体类规范,可以直接使用实体类,如果不规范,还是直接使用JSONObject比较好。(待测试)
6.JsonResponseBodyConverter 在这里面处理返回结果的解析,因为实体类的不规范,gson解析不行,所以需自行处理,在我们需要实体类被解析的时候,实体类必须实现ParseInterface接口并实现T parse(JSONObject jsonObject)方法,因为JsonResponseBodyConverter里面处理解析就是根据该接口的解析方法进行解析的,如果不实现该接口或者该接口的解析方法体为空,那实体类将不能被完整解析,另外需要注意的是,该解析只支持解析为T或List,不支持解析成Map什么的。
7.ParseInterface 该类就是被解析的实体类需要实现的接口
Retrofit工具类的使用
1.在APIService中声明接口和参数
/*
@Query @QueryMap : 用于Http Get请求传递参数
@Field : 用于Post方式传递参数,需要在接口方法上添加@FormUrlEncoded,即以表单的方式传递参数
@Body : 用于Post,根据转换方式将实例对象转化为对应字符串传递参数,比如Retrofit添加GsonConverterFactory则是将body转化为gson字符串进行传递
@Path : 用于URL上占位符{}
@Part : 配合@Multipart使用,一般用于文件上传
@Header : 添加HttpHeader
@Headers : 跟@Header作用一样,只是使用方式不一样,@Header是作为请求方法的参数传入,@Headers是以固定方式直接添加到请求方法上
*/
String USER_INFO = "user/{user_id}/info";
String USER_LIST = "user/{id}/{type}";
@GET(USER_INFO)
Call<User> userDetail(@Path("user_id") Integer userId, @QueryMap Map<String, String> map);
@GET(USER_LIST)
Call<List<User>> userList(@Path("id") Integer userId, @Path("type") String type, @Query("seq") String seq, @Query("length") Integer length, @Query("post_id") Integer postId);
2.将要被解析的实体类实现ParseInterface接口,并实现解析接口,例如:
@Override
public User parse(JSONObject jsonObject) {
try {
return ServerHandler.getUser(jsonObject, null, null, null);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
3.进行网络请求
Map<String, String> map = new HashMap<>();
map.put("kind", "summary");
Call<User> userCall = RetrofitClient.getInstance().getApiService().userDetail(ServerInterfaceHandler.getCurrentUserId(), map);
userCall.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
LogUtils.d("thread_onResponse", Thread.currentThread().getName() + "-" + Thread.currentThread().getId());
User user = response.body();
//需要判断是否为空,因为不能正常解析的时候(只要不出异常也会回调onResponse,出异常则回调onFailure)这里会出现空指针的情况
if(user != null) {
textView.setText(user.getName());
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
ToastUtils.toastAbove(TestActivity.this, "请求失败");
}
});
4.可以对请求进行取消,调用userCall.cancel()方法,比如在界面销毁的时候就可以取消当前正在请求的接口。
5.对同一个接口再次请求userCall.clone().enqueue(…);