资料
Android:手把手带你 深入读懂 Retrofit 2.0 源码Retrofit源码解析从动态代理角度看Retrofit,这才是Retrofit的精髓!
square/retrofitandroid_retrofit的使用(GET)
Retrofit2源码分析:架构全面解析
Retrofit2【Android】Retrofit网络请求参数注解,@Path、@Query、@QueryMap…
Retrofit源码解析从动态代理角度看Retrofit,这才是Retrofit的精髓!
square/retrofitandroid_retrofit的使用(GET)
Retrofit基本使用和源码解析 https://github.com/guiying712/AndroidModulePattern使用Retrofit2封装适用于组件化项目的网络库
用法
public interface GetRequest_Interface {
@GET("openapi.do?keyfrom=abc&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Call<Reception> getCall(@Field("name") String name);
// @GET注解的作用:采用Get方法发送网络请求
// getCall() = 接收网络请求数据的方法
// 其中返回类型为Call<*>,*是接收数据的类(即上面定义的Translation类)
// 如果想直接获得Responsebody中的内容,可以定义网络请求返回值为Call<ResponseBody>
}
public interface GetRequest_Interface {
/**
* method:网络请求的方法(区分大小写)
* path:网络请求地址路径
* hasBody:是否有请求体
*/
@HTTP(method = "GET", path = "blog/{id}", hasBody = false)
Call<ResponseBody> getCall(@Path("id") int id);
// {id} 表示是一个变量
// method 的值 retrofit 不会做处理,所以要自行保证准确
}
public interface GetRequest_Interface {
/**
*表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
* <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值
*/
@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);
/**
* {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型
* 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息),
*/
@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);
}
// @Header
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
// @Headers
@Headers("Authorization: authorization")
@GET("user")
Call<User> getUser()
// 以上的效果是一致的。
// 区别在于使用场景和使用方式
// 1. 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头
// 2. 使用方式:@Header作用于方法的参数;@Headers作用于方法
public interface GetRequest_Interface {
/**
*表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
* <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值
*/
@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);
/**
* Map的key作为表单的键
*/
@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded2(@FieldMap Map<String, Object> map);
}
@GET("/")
Call<String> cate(@Query("cate") String cate);
}
// 其使用方式同 @Field与@FieldMap,这里不作过多描述
public interface GetRequest_Interface {
@GET("users/{user}/repos")
Call<ResponseBody> getBlog(@Path("user") String user );
// 访问的API是:https://api.github.com/users/{user}/repos
// 在发起请求时, {user} 会被替换为方法的第一个参数 user(被@Path注解作用)
}
public interface GetRequest_Interface {
@GET
Call<ResponseBody> testUrlAndQuery(@Url String url, @Query("showAll") boolean showAll);
// 当有URL注解时,@GET传入的URL就可以省略
// 当GET、POST...HTTP等方法中没有设置Url时,则必须使用 {@link Url}提供
}
@DELETE("bean/delete")
Observable<CompanyBean> daleteBean(@Query("id") String id);
总体流程
创建Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://github.com")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
动态代理生成可以使用的方法
动态代理的使用
动态代理在Retrofit中的使用
MiniRetrofit.java
public class MiniRetrofit {
String mBaseUrl;
public MiniRetrofit(String baseUrl) {
mBaseUrl = baseUrl;
}
public <T> T create(final Class<T> service) {
return (T)Proxy.newProxyInstance(
service.getClassLoader(),
newe Class<?>{service},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 如果是equals、toString、hashCode方法则直接调用原来的方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
Call<?> call = null;
// 获取被代理的接口的方法注解
Annotation[] annotations = method.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
// 如果找到对应的Get注解, 则将Get注解中的url和mBaseUrl拼接在一起
if (annotation instanceof Get) {
String path = ((Get) annotation).value();
String url = mBaseUrl + "/" + path;
System.out.println("url:"+url);
// 通过OkHttp请求url, 并将结果回调到外部
final OkHttpClient okHttpClient = new OkHttpClient().newBuilder().build();
final Request request = new Request.Builder()
.url(url)
.build();
call = new Call<Object>() {
@Override
public void enqueue(final CallBack<Object> callBack) {
okHttpClient.newCall(request).enqueue(new Callback(){
@Override
public void onFailure(Call call, IOException e) {
callBack.onFail(e);
}
@Override
public void onResonse(Call call, Response response) {
callBack.onResponse(response.body().string());
}
});
}
};
}
}
}
}
);
}
static class Builder {
String baseUrl;
public Builder baseUrl(String baseUrl) {
this.baseUrl = baseUrl;
return this;
}
public MiniRetrofit build() {
return new MiniRetrofit(baseUrl);
}
}
}
Proxy.newProxyInstance()总结:
- 第一个参数是:ClassLoader, 第二个参数是:Class<?>[](数组),第三个参数:InvocationHandler回调类
- loadService调用需要的方法,并保存在集合中
ServiceMethod.parseAnnotations(Retrofit, Method)
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 获取注解中的参数
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
// 实际要调用的方法
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
RequestFactory.parseAnnotations
解析方法上的请求参数(注解上面的参数)
HttpServiceMethod.parseAnnotations
通过反射调用具体的方法,里面使用了代理方法