一键归纳okhttp3+retrofit2架构,反射+注解+retrofit手写框架
下面两篇文章是我觉得理解比较透彻和详细的文章
一、首先你需要了解什么是动态代理
二、其次你要了解一下retrofit2的基本使用以及源码解析
Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装,网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责网络请求接口的封装。
三、简单的利用注解反射实现retrofit网络请求,有助于理解其中的基本原理
此处仅为基本使用,适配器和转换器未使用。距离完整的框架还差一大截
下面开始看代码
元数据
public interface WeatherApi {
@POST("/v3/weather/weatherInfo")
@FormUrlEncoded
Call<ResponseBody> postWeather(@Field("city") String city, @Field("key") String key);
@GET("/v3/weather/weatherInfo")
Call<ResponseBody> getWeather(@Query("city") String city, @Query("key") String key);
}
看一下自定义的注解,用于方法注解,适用于运行期
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {
String value() default "";
}
@Target(METHOD)
@Retention(RUNTIME)
public @interface POST {
String value() default "";
}
自定义的retrofit
public class MyRetrofit {
final Map<Method, ServiceMethod> serviceMethodCache = new ConcurrentHashMap<>();
final Call.Factory callFactory;
final HttpUrl baseUrl;
MyRetrofit(Call.Factory callFactory, HttpUrl baseUrl) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
}
public <T> T create(final Class<T> service) {
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//解析这个method 上所有的注解信息
ServiceMethod serviceMethod = loadServiceMethod(method);
//args:
return serviceMethod.invoke(args);
}
});
}
private ServiceMethod loadServiceMethod(Method method) {
//先不上锁,避免synchronized的性能损失
ServiceMethod result = serviceMethodCache.get(method);
if (result != null) return result;
//多线程下,避免重复解析,
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
/**
* 构建者模式,将一个复杂对象的构建和它的表示分离,可以使使用者不必知道内部组成的细节。
*/
public static final class Builder {
private HttpUrl baseUrl;
//Okhttp->OkhttClient
private okhttp3.Call.Factory callFactory; //null
public Builder callFactory(okhttp3.Call.Factory factory) {
this.callFactory = factory;
return this;
}
public Builder baseUrl(String baseUrl) {
this.baseUrl = HttpUrl.get(baseUrl);
return this;
}
public MyRetrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
return new MyRetrofit(callFactory, baseUrl);
}
}
}
接下来是ServiceMethod 记录请求类型 参数 完整地址
public class ServiceMethod {
private final Call.Factory callFactory;
private final String relativeUrl;
private final boolean hasBody;
private final ParameterHandler[] parameterHandler;
private FormBody.Builder formBuild;
HttpUrl baseUrl;
String httpMethod;
HttpUrl.Builder urlBuilder;
public ServiceMethod(Builder builder) {
//获取代理对象myretrofit的参数,以便封装请求参数
baseUrl = builder.enjoyRetrofit.baseUrl;
callFactory = builder.enjoyRetrofit.callFactory;
httpMethod = builder.httpMethod;
relativeUrl = builder.relativeUrl;
hasBody = builder.hasBody;
parameterHandler = builder.parameterHandler;
//如果是有请求体,创建一个okhttp的请求体对象
if (hasBody) {
formBuild = new FormBody.Builder();
}
}
public Object invoke(Object[] args) {
/**
* 1 处理请求的地址与参数
* 这里也是在invoke里要实现的网络请求
*/
for (int i = 0; i < parameterHandler.length; i++) {
ParameterHandler handlers = parameterHandler[i];
//handler内本来就记录了key,现在给到对应的value
handlers.apply(this, args[i].toString());
}
//获取最终请求地址
HttpUrl url;
if (urlBuilder == null) {
urlBuilder = baseUrl.newBuilder(relativeUrl);
}
url = urlBuilder.build();
//请求体
FormBody formBody = null;
if (formBuild != null) {
formBody = formBuild.build();
}
Request request = new Request.Builder().url(url).method(httpMethod, formBody).build();
return callFactory.newCall(request);
}
// get请求, 把 k-v 拼到url里面
public void addQueryParameter(String key, String value) {
if (urlBuilder == null) {
urlBuilder = baseUrl.newBuilder(relativeUrl);
}
urlBuilder.addQueryParameter(key, value);
}
//Post 把k-v 放到 请求体中
public void addFiledParameter(String key, String value) {
formBuild.add(key, value);
}
public static class Builder {
private final MyRetrofit enjoyRetrofit;
private final Annotation[] methodAnnotations;
private final Annotation[][] parameterAnnotations;
ParameterHandler[] parameterHandler;
private String httpMethod;
private String relativeUrl;
private boolean hasBody;
public Builder(MyRetrofit enjoyRetrofit, Method method) {
this.enjoyRetrofit = enjoyRetrofit;
//获取方法上的所有的注解
methodAnnotations = method.getAnnotations();
//获得方法参数的所有的注解 (一个参数可以有多个注解,一个方法又会有多个参数)
parameterAnnotations = method.getParameterAnnotations();
}
public ServiceMethod build() {
/**
* 利用反射获取注解,并添加请求体里
* 1 解析方法上的注解, 只处理POST与GET
*/
for (Annotation methodAnnotation : methodAnnotations) {
if (methodAnnotation instanceof POST) {
//记录当前请求方式
this.httpMethod = "POST";
//记录请求url的path
this.relativeUrl = ((POST) methodAnnotation).value();
// 是否有请求体
this.hasBody = true;
} else if (methodAnnotation instanceof GET) {
this.httpMethod = "GET";
this.relativeUrl = ((GET) methodAnnotation).value();
this.hasBody = false;
}
}
/**
* 2 解析方法参数的注解
*/
int length = parameterAnnotations.length;
parameterHandler = new ParameterHandler[length];
for (int i = 0; i < length; i++) {
// 一个参数上的所有的注解
Annotation[] annotations = parameterAnnotations[i];
// 处理参数上的每一个注解
for (Annotation annotation : annotations) {
//todo 可以加一个判断:如果httpMethod是get请求,现在又解析到Filed注解,可以提示使用者使用Query注解
if (annotation instanceof Field) {
//得到注解上的value: 请求参数的key
String value = ((Field) annotation).value();
parameterHandler[i] = new ParameterHandler.FiledParameterHandler(value);
} else if (annotation instanceof Query) {
String value = ((Query) annotation).value();
parameterHandler[i] = new ParameterHandler.QueryParameterHandler(value);
}
}
}
return new ServiceMethod(this);
}
}
}
public abstract class ParameterHandler {
abstract void apply(ServiceMethod serviceMethod, String value);
static class QueryParameterHandler extends ParameterHandler {
String key;
public QueryParameterHandler(String key) {
this.key = key;
}
//serviceMethod: 回调
@Override
void apply(ServiceMethod serviceMethod, String value) {
serviceMethod.addQueryParameter(key,value);
}
}
static class FiledParameterHandler extends ParameterHandler {
String key;
public FiledParameterHandler(String key) {
this.key = key;
}
@Override
void apply(ServiceMethod serviceMethod, String value) {
serviceMethod.addFiledParameter(key,value);
}
}
}
最后调用、点击事件卸在view里。不展示了
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private EnjoyWeatherApi enjoyWeatherApi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyRetrofit enjoyRetrofit = new MyRetrofit.Builder().baseUrl("https://restapi.amap.com").build();
enjoyWeatherApi = enjoyRetrofit.create(EnjoyWeatherApi.class);
}
public void enjoyPost(View view) {
okhttp3.Call call = enjoyWeatherApi.postWeather("110101", "ae6c53e2186f33bbf240a12d80672d1b");
call.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(okhttp3.Call call, IOException e) {
}
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
Log.i(TAG, "onResponse enjoy post: " + response.body().string());
response.close();
}
});
}
}