美文网首页
网易云微专业安卓-解耦的套路,核心的代理,手撸Retrofit核

网易云微专业安卓-解耦的套路,核心的代理,手撸Retrofit核

作者: 呵呵_9e25 | 来源:发表于2020-03-17 18:34 被阅读0次

文章纯属个人学习的代码实现

网易云微专业公开课这节课 手写了这个Retrofit的简单实现,包含了基本的功能,能正常网络请求

我们先看一段 Retrofit请求的基本形式,代码如下

public class RetrofitTest {
    private final static String IP = "144.34.161.97";
    private final static String KEY = "aa205eeb45aa76c6afe3c52151b52160";
    private final static String BASE_URl = "http://apis.juhe.cn/";

    interface HOST {
        @GET("/ip/ipNew")
        Call get(@Query("ip") String ip, @Query("key") String key);
    }

    @Test
    public void retrofitTest() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URl)
                .build();
        HOST host = retrofit.create(HOST.class);
        Call call = host.get(IP, KEY);
        try {
            Response response = call.execute();
            if (response != null && response.body() != null) {
                System.out.println(response.body().string());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

这里包含三个部分
第一部分

    private final static String IP = "144.34.161.97";
    private final static String KEY = "aa205eeb45aa76c6afe3c52151b52160";
    private final static String BASE_URl = "http://apis.juhe.cn/";

这里主要是我们构建请求的一些基本变量
第二部分

 interface HOST {
        @GET("/ip/ipNew")
        Call get(@Query("ip") String ip, @Query("key") String key);
    }

熟悉Retrofit的都知道 ,这是Retrofitrestful风格的一种请求接口约定方式

第三部分

@Test
    public void retrofitTest() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URl)
                .build();
        HOST host = retrofit.create(HOST.class);
        Call call = host.get(IP, KEY);
        try {
            Response response = call.execute();
            if (response != null && response.body() != null) {
                System.out.println(response.body().string());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

这里就是我们用Retrofit构建一个基本的 请求的过程
首先我们需要一个 Retrofit对象

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URl)
                .build();

这里主要是通过一个工厂模式配置一些基本信息,比如请求地址的域名,可以看看合理的基本实现

public static class Builder {
        private HttpUrl baseUrl;
        private Call.Factory  callFactory;

        public Builder baseUrl(String base_uRl) {
            if (base_uRl.isEmpty()){
                throw new NullPointerException("baseUrl为空");
            }
            this.baseUrl= HttpUrl.parse(base_uRl);
            return this;
        }

        public Builder baseUrl(HttpUrl base_uRl) {
            if (base_uRl==null){
                throw new NullPointerException("baseUrl为空");
            }
            this.baseUrl= base_uRl;
            return this;
        }

        public Retrofit build() {
            if(this.baseUrl==null){
                throw new IllegalStateException("baseUrl 必须提供");
            }
            if(this.callFactory==null){
                 callFactory=new OkHttpClient();
            }
            return new Retrofit(this);
        }
    }

主要看看这个build()方法,初始化了baseUrlOkHttpClient对象,这个是OkHttpClient对象是用来执行Okhttp网络请求的


我们接着看着里

 HOST host = retrofit.create(HOST.class);

通过我们刚刚构造出来的retrofit对象的create方法去返回一个 HOST对象,我们可以看看这里怎么实现的。

public <T> T create(Class<T> t) {
        return (T) Proxy.newProxyInstance(t.getClassLoader(), new Class[]{t}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //在动态代理里面获取方法请求的相关参数和注解
                ServiceMethod serviceMethod=loadServiceMethod(method);
                //然后做请求
                return new OkhttpCall(serviceMethod,args);
            }
        });
    }

我们可以看到这其实就是动态代理,通过代理的形式实现AOP切入,在用户调用这句话Call call = host.get(IP, KEY);的时候,这里的invoke方法 就会被调用,从而实现参数拦截,方法前后处理等功能。

而这里其实就是通过loadServiceMethod(method)方法来完成参数和请求类型等解析。

主要方式当然是用到反射。我们可以大概看看代码

 private ServiceMethod loadServiceMethod(Method method) {
        //先去取  如果缓存里面有咱们就返回出去
        ServiceMethod serviceMethod=serviceMethodMap.get(method);
        if(serviceMethod!=null)return serviceMethod;

        //如果没有  我们就需要注意线程同步问题
        synchronized (serviceMethodMap){
            serviceMethod=serviceMethodMap.get(method);
            if(serviceMethod==null){
                serviceMethod=new ServiceMethod.Builder(this,method).build();
            }
        }

        return serviceMethod;

    }

这里只做了一个取缓存里面的method的一个处理,可以看出来这里加了一个synchronized (serviceMethodMap)防止线程同步出现问题。

核心解析参数啥的都在ServiceMethod.Builder(this,method).build()里面,我们接着看

   public Builder(Retrofit retrofit, Method method) {
           this.retrofit=retrofit;
           this.method=method;
           this.methodAnnotations=method.getAnnotations();
           this.parameterAnnotationsArray=method.getParameterAnnotations();
        }
 public ServiceMethod build() {
            for (Annotation methodAnnotation : methodAnnotations) {
                  //解析方法注解 比如GET POST
                  parseMethodAnnotation(methodAnnotation);
            }

            //开始解析方法参数注解
            int parameterLength = parameterAnnotationsArray.length;
            parameterHandlers = new ParameterHandler[parameterLength];
            for (int i = 0; i < parameterLength; i++) {
                //获取方法的参数的所有注解
                Annotation[] annotations = parameterAnnotationsArray[i];
                if(annotations == null){
                    throw new NullPointerException("不合规矩");
                }
                //开始解析Query这些参数
                parameterHandlers[i] = parseParameter(i,annotations);
            }
            return  new ServiceMethod(this);

        }

我们关注这两行代码

    this.methodAnnotations=method.getAnnotations();
           this.parameterAnnotationsArray=method.getParameterAnnotations();

这其实就是反射里面的获取方法的注释和获取方法的参数注解。

我们再继续看看ServiceMethod里的的核心方法

 /**
     * 最后要的一个方法 实际生成一个 请求对象
     */
    okhttp3.Call toCall(Object... args){
        //我们需要构建一个请求对象
        RequestBuilder requestBuilder=new RequestBuilder(httpMethod,baseUrl,relativeUrl,hasBody);
        ParameterHandler[] handlers = this.parameterHandlers;
        int  argumentCount=args!=null?args.length:0;
        if (argumentCount != handlers.length) {
            //方法真实的参数个数不等于收集的参数个数
            throw new IllegalArgumentException("");
        }

        for (int i = 0; i < argumentCount; i++) {
            //填充参数到对应的注解去
            handlers[i].apply(requestBuilder,args[i].toString());
        }
        return callFactory.newCall(requestBuilder.build());
    }

看不懂没关系,我就告诉你,是做了参数传值,然后构建了一个Request对象,然后用callFactory.newCall(requestBuilder.build());完成请求,这个callFactory其实就是我们Retrofit里面传入的OkHttpClient对象
然后我们基本就完成了请求
大家想了解更多直接去我的github看代码实现

相关文章

网友评论

      本文标题:网易云微专业安卓-解耦的套路,核心的代理,手撸Retrofit核

      本文链接:https://www.haomeiwen.com/subject/dpntyhtx.html