源代码
GitHub源代码
本文目标
Retrofit核心代码简易版手写实现(仅供学习)
基本用法
public void click(View view) {
RetrofitClient
.getServiceApi()
.userLogin("yd", "123456")
.enqueue(new Callback<UserLoginResult>() {
@Override
public void onResponse(Call<UserLoginResult> call, Response<UserLoginResult> response) {
final String result = response.body.toString();
Log.i("TAG",result);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,result,Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onFailure(Call<UserLoginResult> call, Throwable t) {
Log.e("TAG",t.getMessage());
}
});
}
从最简单最基础的用法开始入手,首先先看RetrofitClient
类
RetrofitClient
/**
* Author: 信仰年轻
* Date: 2021-07-02 15:02
* Email: hydznsqk@163.com
* Des:
*/
public class RetrofitClient {
private final static ServiceApi mServiceApi;
static {
//1.首先创建了一个OkHttpClient的对象
OkHttpClient okHttpClient = new OkHttpClient
.Builder()
.addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.i("TAG", message);
}
}).setLevel(HttpLoggingInterceptor.Level.BODY))
.build();
//2.然后创建Retrofit类设置baseUrl并把OkHttpClient给添加进去
Retrofit retrofit = new Retrofit
.Builder()
// 访问后台接口的主路径
.baseUrl("https://www.fastmock.site/mock/b5b5b4f8bf5a7178e46771346c7940ca/YdHttpServer/")
// 添加 OkHttpClient,不添加默认就是 光杆 OkHttpClient
.client(okHttpClient)
.build();
//3.创建一个 实例对象
mServiceApi = retrofit.create(ServiceApi.class);
}
public static ServiceApi getServiceApi() {
return mServiceApi;
}
}
- 1.首先创建了一个
OkHttpClient
的对象 - 2.然后创建
Retrofit
类设置baseUrl
并把OkHttpClient
给添加进去 - 3.
retrofit
去创建ServiceApi
接口的实例对象
基本用法都看完了,然后我们开始看Retrofit
类
1.Retrofit
/**
* Author: 信仰年轻
* Date: 2021-07-01 17:44
* Email: hydznsqk@163.com
* Des: 1.动态代理
* 2.解析方法上的注解和解析参数上的注解
* 3.封装OkHttp请求
*/
public class Retrofit {
String mBaseUrl;
okhttp3.Call.Factory mCallFactory;
private Map<Method, ServiceMethod> serviceMethodMap = new ConcurrentHashMap<>();
public Retrofit(Builder builder) {
this.mBaseUrl = builder.baseUrl;
this.mCallFactory = builder.callFactory;
}
/**
* 1.动态代理
*/
public <T> T create(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 {
//每执行一个方法都会来到这里
// 判断是不是 Object 的方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//2.解析方法上的注解和解析参数上的注解
ServiceMethod serviceMethod = loadServiceMethod(method);
//3.封装OkHttp请求
OkHttpCall okHttpCall = new OkHttpCall(serviceMethod, args);
return okHttpCall;
}
});
}
/**
* 2.解析方法上的注解和解析参数上的注解
*/
private ServiceMethod loadServiceMethod(Method method) {
ServiceMethod serviceMethod = serviceMethodMap.get(method);
if (serviceMethod == null) {
//创建ServiceMethod,把Retrofit和Method都传递进去进行解析
serviceMethod = new ServiceMethod.Builder(this, method).build();
serviceMethodMap.put(method, serviceMethod);
}
return serviceMethod;
}
public static class Builder {
String baseUrl;
okhttp3.Call.Factory callFactory;
public Builder baseUrl(String baseUrl) {
this.baseUrl = baseUrl;
return this;
}
public Builder client(okhttp3.Call.Factory factory) {
this.callFactory = factory;
return this;
}
public Retrofit build() {
if (callFactory == null) {
callFactory = new OkHttpClient();
}
return new Retrofit(this);
}
}
}
Retrofit
类一共做了3件事情
- 1.动态代理
- 2.解析方法上的注解和解析参数上的注解
- 3.封装OkHttp请求
第1步,动态代理其目的就是为了解耦,每执行一个接口方法都会来到动态代理的invoke
方法,代码如下
/**
* 1.动态代理
*/
public <T> T create(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 {
//每执行一个方法都会来到这里
// 判断是不是 Object 的方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//2.解析方法上的注解和解析参数上的注解
ServiceMethod serviceMethod = loadServiceMethod(method);
//3.封装OkHttp请求
OkHttpCall okHttpCall = new OkHttpCall(serviceMethod, args);
return okHttpCall;
}
});
}
第2步,解析方法上的注解和参数上的注解,具体代码如下
private Map<Method, ServiceMethod> serviceMethodMap = new ConcurrentHashMap<>();
/**
* 2.解析方法上的注解和解析参数上的注解
*/
private ServiceMethod loadServiceMethod(Method method) {
ServiceMethod serviceMethod = serviceMethodMap.get(method);
if (serviceMethod == null) {
//创建ServiceMethod,把Retrofit和Method都传递进去进行解析
serviceMethod = new ServiceMethod.Builder(this, method).build();
serviceMethodMap.put(method, serviceMethod);
}
return serviceMethod;
}
第3步,就是封装成OkHttpCall请求
//3.封装OkHttp请求
OkHttpCall okHttpCall = new OkHttpCall(serviceMethod, args);
我们来看下方法上的注解和参数上的注解是如何被解析的,来看ServiceMethod
这个类
2.ServiceMethod,解析注解
/**
* Author: 信仰年轻
* Date: 2021-07-01 18:49
* Email: hydznsqk@163.com
* Des: 解析方法上的注解和参数上的注解
*/
public class ServiceMethod {
private final Retrofit mRetrofit;
private final Method mMethod;
private String mHttpMethod; //请求的方式 是GET还是POST
private String mRelativeUrl;//相对路径
private final ParameterHandler[] mParameterHandlers;
public ServiceMethod(Builder builder) {
this.mRetrofit = builder.mRetrofit;
this.mMethod = builder.mMethod;
this.mHttpMethod = builder.mHttpMethod;
this.mRelativeUrl = builder.mRelativeUrl;
this.mParameterHandlers = builder.mParameterHandlers;
}
/**
* 创建一个新的Call
*/
public okhttp3.Call createNewCall(Object[] args) {
//把基础url,相对url,请求方式(get或post),mParameterHandler和真正的参数传递进去
RequestBuilder requestBuilder = new RequestBuilder(mRetrofit.mBaseUrl, mRelativeUrl, mHttpMethod, mParameterHandlers, args);
return mRetrofit.mCallFactory.newCall(requestBuilder.build());
}
/**
* 解析ResponseBody
*/
public <T> T parseBody(ResponseBody responseBody) {
// 获取解析类型 T 获取方法返回值的类型
Type returnType = mMethod.getGenericReturnType();// 返回值对象
Class <T> dataClass = (Class <T>) ((ParameterizedType) returnType).getActualTypeArguments()[0];
// 解析工厂去转换
Gson gson = new Gson();
T body = gson.fromJson(responseBody.charStream(),dataClass);
return body;
}
public static class Builder {
private final Retrofit mRetrofit;
private final Method mMethod;
private String mHttpMethod; //请求的方式 是GET还是POST
private String mRelativeUrl;//相对路径
private final Annotation[] mMethodAnnotations;
private final Annotation[][] mParameterAnnotations;
private final ParameterHandler[] mParameterHandlers;
public Builder(Retrofit retrofit, Method method) {
this.mRetrofit = retrofit;
this.mMethod = method;
//方法注解的数组
mMethodAnnotations = method.getAnnotations();
//参数注解的二维数组,为什么是二维数组呢,因为1个参数上有可能会有多个注解,所以每个参数对应一个数组,那多个参数就是二维数组了
mParameterAnnotations = method.getParameterAnnotations();
mParameterHandlers = new ParameterHandler[mParameterAnnotations.length];
}
public ServiceMethod build() {
//1.解析方法上的注解
for(Annotation annotation:mMethodAnnotations){
parseAnnotationMethod(annotation);
}
//2.解析参数注解
for(int x=0;x<mParameterAnnotations.length;x++){
Annotation annotation = mParameterAnnotations[x][0];
//在这里只有Query这个注解
if(annotation instanceof Query){
// 一个一个封装成 ParameterHandler,不同的参数注解选择不同的策略
//传进去的就是 参数的 key = userName ,password
mParameterHandlers[x]=new ParameterHandler.Query(((Query) annotation).value());
}
}
return new ServiceMethod(this);
}
//1.解析方法上的注解
private void parseAnnotationMethod(Annotation annotation) {
if(annotation instanceof GET){
parseMethodAndPath("GET",((GET) annotation).value());
}else if(annotation instanceof POST){
parseMethodAndPath("POST",((POST) annotation).value());
}
//还有一大堆其他解析...
}
private void parseMethodAndPath(String method, String value) {
this.mHttpMethod =method;
this.mRelativeUrl =value;
}
}
}
可以发现是在Builder
内部类的build()
方法去解析方法上的注解和参数注解的,解析完成后给赋值成成员变量
到这里,注解上的value
已经被解析出来了,包括是什么请求GET
还是POST
,相对路径,以及Query
的key
和value
然后给赋值给成员变量
在解析参数注解的时候我们需要用到ParameterHandler
这个类,因为会有很多不同的注解,我们需要一个一个封装成 ParameterHandler,不同的参数注解选择不同的策略,在这里只是写了Query
注解的处理策略
/**
* Author: 信仰年轻
* Date: 2021-07-02 14:52
* Email: hydznsqk@163.com
* Des:
*/
public interface ParameterHandler<T> {
void apply(RequestBuilder requestBuilder, T value);
class Query<T> implements ParameterHandler<T> {
private String key; // 保存 就是参数的 key = userName ,password
public Query(String key) {
this.key = key;
}
@Override
public void apply(RequestBuilder requestBuilder, T value) {
requestBuilder.addQueryName(key, value.toString());
}
}
}
3.OkHttpCall
/**
* Author: 信仰年轻
* Date: 2021-07-01 18:58
* Email: hydznsqk@163.com
* Des:
*/
public class OkHttpCall<T> implements Call<T> {
private ServiceMethod mServiceMethod;
private Object[] mArgs;
public OkHttpCall(ServiceMethod serviceMethod, Object[] args) {
this.mServiceMethod = serviceMethod;
this.mArgs = args;
}
@Override
public void enqueue(final Callback<T> callback) {
// 发起一个请求,给一个回调就完结了
Log.e("TAG", "正式发起请求");
//1.建一个新的Call
okhttp3.Call call = mServiceMethod.createNewCall(mArgs);
//2.发起请求
call.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(okhttp3.Call call, IOException e) {
if (callback != null) {
callback.onFailure(OkHttpCall.this, e);
}
}
@Override
public void onResponse(okhttp3.Call call, Response response) throws IOException {
//3.解析数据
//涉及到解析,不能在这里写上,ConvertFactory
com.retrofit.write.retrofit.Response objectResponse = new com.retrofit.write.retrofit.Response();
objectResponse.body = mServiceMethod.parseBody(response.body());
if (callback != null) {
callback.onResponse(OkHttpCall.this, objectResponse);
}
}
});
}
}
该类的enqueue
方法也只是干了3件事
- 1.建一个新的Call
- 2.发起请求
- 3.解析数据
在createNewCall
方法中我们需要使用到RequestBuilder
类来创建Request
对象
public class Retrofit {
......
/**
* 创建一个新的Call
*/
public okhttp3.Call createNewCall(Object[] args) {
//把基础url,相对url,请求方式(get或post),mParameterHandler和真正的参数传递进去
RequestBuilder requestBuilder = new RequestBuilder(mRetrofit.mBaseUrl, mRelativeUrl, mHttpMethod, mParameterHandlers, args);
return mRetrofit.mCallFactory.newCall(requestBuilder.build());
}
......
}
/**
* Author: 信仰年轻
* Date: 2021-07-02 14:53
* Email: hydznsqk@163.com
* Des:
*/
public class RequestBuilder {
ParameterHandler<Object>[] mParameterHandlers;
Object[] args;
HttpUrl.Builder httpUrl;
public RequestBuilder(String baseUrl, String relativeUrl, String httpMethod, ParameterHandler[] parameterHandlers, Object[] args) {
this.mParameterHandlers = (ParameterHandler<Object>[]) parameterHandlers;
this.args = args;
this.httpUrl = HttpUrl.parse(baseUrl+relativeUrl).newBuilder();
}
public Request build() {
int count = args.length;
for (int i=0;i < count;i++) {
// userName = yd
mParameterHandlers[i].apply(this,args[i]);
}
// POST 等等
Request request = new Request
.Builder()
.url(httpUrl.build())
.build();
return request;
}
//https://www.fastmock.site/mock/b5b5b4f8bf5a7178e46771346c7940ca/YdHttpServer/login?userName=yd&password=123456
public void addQueryName(String key, String value) {
// userName = yd&password = 123456
httpUrl.addQueryParameter(key,value);
}
}
最后就是请求成功之后的解析数据了
public class Retrofit {
......
/**
* 解析ResponseBody
*/
public <T> T parseBody(ResponseBody responseBody) {
// 获取解析类型 T 获取方法返回值的类型
Type returnType = mMethod.getGenericReturnType();// 返回值对象
Class <T> dataClass = (Class <T>) ((ParameterizedType) returnType).getActualTypeArguments()[0];
// 解析工厂去转换
Gson gson = new Gson();
T body = gson.fromJson(responseBody.charStream(),dataClass);
return body;
}
......
}
最后通过回调接口把数据返回出去,整个流程就结束了,具体可以参考Demo
网友评论