Android知名三方库Retrofit(二) - 手写核心代码

源代码
GitHub源代码

本文目标

Retrofit核心代码简易版手写实现(仅供学习)

基本用法

    public void click(View view) {
        RetrofitClient
                .getServiceApi()
                .userLogin("yd", "123456")
                .enqueue(new Callback() {
                    @Override
                    public void onResponse(Call call, Response 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 call, Throwable t) {
                        Log.e("TAG",t.getMessage());
                    }
                });
    }

从最简单最基础的用法开始入手,首先先看RetrofitClient

RetrofitClient

/**
 * Author: 信仰年轻
 * Date: 2021-07-02 15:02
 * Email: [email protected]
 * 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: [email protected]
 * Des: 1.动态代理
 *      2.解析方法上的注解和解析参数上的注解
 *      3.封装OkHttp请求
 */
public class Retrofit {

    String mBaseUrl;
    okhttp3.Call.Factory mCallFactory;
    private Map serviceMethodMap = new ConcurrentHashMap<>();

    public Retrofit(Builder builder) {
        this.mBaseUrl = builder.baseUrl;
        this.mCallFactory = builder.callFactory;
    }

    /**
     * 1.动态代理
     */
    public  T create(Class 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 create(Class 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 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: [email protected]
 * 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 parseBody(ResponseBody responseBody) {
        // 获取解析类型 T 获取方法返回值的类型
        Type returnType = mMethod.getGenericReturnType();// 返回值对象
        Class  dataClass = (Class ) ((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

可以发现是在Builder内部类的build()方法去解析方法上的注解和参数注解的,解析完成后给赋值成成员变量
到这里,注解上的value已经被解析出来了,包括是什么请求GET还是POST,相对路径,以及Querykeyvalue然后给赋值给成员变量
在解析参数注解的时候我们需要用到ParameterHandler这个类,因为会有很多不同的注解,我们需要一个一个封装成 ParameterHandler,不同的参数注解选择不同的策略,在这里只是写了Query注解的处理策略

/**
 * Author: 信仰年轻
 * Date: 2021-07-02 14:52
 * Email: [email protected]
 * Des:
 */
public interface ParameterHandler {
    void apply(RequestBuilder requestBuilder, T value);

    class Query implements ParameterHandler {
        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: [email protected]
 * Des:
 */
public class OkHttpCall implements Call {

    private ServiceMethod mServiceMethod;
    private Object[] mArgs;

    public OkHttpCall(ServiceMethod serviceMethod, Object[] args) {
        this.mServiceMethod = serviceMethod;
        this.mArgs = args;
    }

    @Override
    public void enqueue(final Callback 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: [email protected]
 * Des:
 */
public class RequestBuilder {
    ParameterHandler[] mParameterHandlers;
    Object[] args;
    HttpUrl.Builder httpUrl;

    public RequestBuilder(String baseUrl, String relativeUrl, String httpMethod, ParameterHandler[] parameterHandlers, Object[] args) {
        this.mParameterHandlers = (ParameterHandler[]) 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 parseBody(ResponseBody responseBody) {
        // 获取解析类型 T 获取方法返回值的类型
        Type returnType = mMethod.getGenericReturnType();// 返回值对象
        Class  dataClass = (Class ) ((ParameterizedType) returnType).getActualTypeArguments()[0];
        // 解析工厂去转换
        Gson gson = new Gson();
        T body = gson.fromJson(responseBody.charStream(),dataClass);
        return body;
    }
   ......
}

最后通过回调接口把数据返回出去,整个流程就结束了,具体可以参考Demo

你可能感兴趣的:(Android知名三方库Retrofit(二) - 手写核心代码)