美文网首页移动潮流技术android技术专栏Android进阶
Retrofit2.0 源码解析,玩转IOC和AOP, 徒手实现

Retrofit2.0 源码解析,玩转IOC和AOP, 徒手实现

作者: Tamic | 来源:发表于2016-07-18 19:33 被阅读3323次

    简书 :码小白
    原文地址:
    http://www.jianshu.com/p/17305f991ed8


    图于文无关.jpg

    前言

    Retrofit用法和介绍的文章实在是多的数不清,也有很多介绍其内部原理的,但是看过之后,还是让很多人云里雾里, 本篇文章旨在通过自我实现一个自定义的Retrofit,来熟悉了解其Retrofit的内部原理。也帮助针对那些项目很稳定,解决迁移API接口带来的难度问题。

    如果对Retrofit不熟悉的请先阅读Retrofit全介绍:

    Retrofit :https://futurestud.io/blog

    如果阅读外文吃力的话,建议阅读笔者之前的本系列文章

    回顾Retrofit

    Retrofit2.0是SQUARE美国一家移动支付公司最新发布的在Android平台上http访问客户端,具体简单用法列举

    简单列子

    // 创建ApiService
    public interface ApiService {    
        @GET("service/getIpInfo.php")    Call<IpResult> getData(@Query("ip") String ip);
    }
       // 实例化Retrofit
        Retrofit retrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl(url)
                .build();
    
        // 构架ApiServiceImpl
        ApiService apiService = retrofit.create(ApiService.class);
       
         // 执行异步请求
        Call<IpResult> call = apiService.getData("21.22.11.33");
    
        call.enqueue(new Callback<IpResult>() {
            @Override
            public void onResponse(Call<IpResult> call, Response<IpResult> response) {
    
            }
    
            @Override
            public void onFailure(Call<IpResult> call, Throwable t) {
    
            }
        });
    

    代码很简洁,很多人甚是羡慕,想想自己何时才能写出如此优雅的代码,也想弄明白其内部怎么实现的,今天就给大家带来一款Tamic框架,来模仿下Retrofit的实现原理。
    下文开始之前,不会对Retrofit的原理进行理论分析,其实也没这个必要,推荐一篇其他人写的文章:

    接着本次实现方式不会沿用Retrofit基于的okhttp, 因为okHttp本身实现了已进行了线程管理和回调,会给本次demo实现带来一定弊端,所以我选择用了SynchttpClient来做基础请求端,这样才能显得用零基础实现Retrofit, 本次实现需要涉猎到Java反射,依赖注入,控制反转,代理模式,建造者模式,面向接口编程等,这些技术这里不再重复介绍,下面接着看重点。

    准备注解类

    retrofit采用注解实现API,因此也模仿了准备多个注解接口,比如请求类型(GET),参数(Part),头部(header)等,
    为了区分我用Tamic的开头用来做前缀先创建一个注解类TGet

     // 请求方式
     @Target(ElementType.METHOD)
    public @interface TGet {
     String value();
    }
    

    Body 类似于Part

    // 参数
    @Retention(RetentionPolicy.RUNTIME)
      public @interface TBody {
      String value();
    }
    
    注解类.jpg

    其他注解类没多大技术点,贮备好上图的注解类,方式一样,源码就不在列举。

    准备CallBack

    此接口类用来回调http请求结果,采用泛型,方便上层注入数据model,动态解析返回实体

     public interface ICallback<T> {
    
     void success(T t);
     void failed(Throwable e);
    

    }

    Platform

    Platform用来调度多个请求线程,

     public class Platform {
     private static final Platform PLATFORM = findPlatform();
    
    public static Platform get() {
        Log.v(TamicHttpClient.TAG, PLATFORM.getClass().toString());
        return PLATFORM;
    }
    
    private static Platform findPlatform() {
        try {
            Class.forName("android.os.Build");
            if (Build.VERSION.SDK_INT != 0) {
                return new Android();
            }
        } catch (ClassNotFoundException ignored) {
        }
        return new Platform();
    }
    
    public Executor defaultCallbackExecutor() {
        return new HandleThreadPool().getExecutor();
    }
    
    public Object execute(Runnable runnable) {
        defaultCallbackExecutor().execute(runnable);
        return null;
    }
    
    static class Android extends Platform {
        @Override
        public Executor defaultCallbackExecutor() {
            return new HandleThreadPool().getExecutor();
        }
      }
    

    Tamic

    构建类似Retrofit一样的bulid模式的API工厂,此类主要用反射解析和代理ApiService,用来执行具体网络访问请求,动态解析泛型数据模型,回调服务端返回的请求结果,返回上层便于UI更新。

      Tamic(Context context, String baseUrl, AsyncHttpClient client) {
         this.context = context;
         this.baseUrl = baseUrl;
         this.client = client;
    }
    
    /**
     * public interface CategoryService {
     * @POST("category/{cat}/")
     * Call<List<Item>> categoryList(@Path("cat") String a, @Query("page") int b);
     * }
     */
    public <T> T create(final Class<T> clazz) {
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
                new Class[]{clazz},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                        performeParser(proxy, method, args);
                        return execute();
                    }
                });
    }
    

    此是Tamic内部类builder大致图,具体代码可以去github阅读,主要用来构建上层添加baseUrl,超时等接口,实例化AsyncHttpClient等

    builder.jpg

    线程池工厂

    用来管理和复用线程,避免线程溢出造成内存泄露,不是本次关注的点,略去


    实现好了自己的Retrofit,接下来我们看看怎样使用,观察下和Retrofit用法有什么区别?

    Tamic用法

    依赖

    repositories {    jcenter()    
                     maven { url "https://jitpack.io" }
    

    }

    dependencies {
       ....
    compile 'com.tamic:tamicLibrary:1.0.2'
       .....
    
    }
    

    实例化Tamic (Retrofit)

     Tamic tamic = new Tamic.Builder(MainActivity.this)
                .baseUrl("http://ip.taobao.com/")
                .connectTimeout(5)
                .addLog(true)
                .build();
    

    APIService

    public interface ApiService {
    
    @TGet("service/getIpInfo.php")
    Call<IpResult> getData(@TBody("ip") String ip,ICallback<IpResult> callBack);
                    
                    }
    

    Create Service

     ApiService service = tamic.create(ApiService.class);
    

    Execute

      service.getData("21.22.11.33", new ICallback<IpResult>() {
            @Override
            public void success(IpResult ipResult) {
                // todo
            }
    
            @Override
            public void failed(Throwable e) {
                // todo
            }
        });
    

    华丽结束

    给下面按钮给个点击事件,用来执行请求,在回调中显示一条Toast, 看看测试结果:

    测试结果

    数据成功请求到,并且被框架自动解析返回JavaBean

    既然功能和Retrofit很相似,和我们的Retrofit几乎一摸一样,我们再看看的工程配置

    compile 'com.loopj.android:android-async-http:1.4.9'
    compile 'com.alibaba:fastjson:1.2.12'

    果不其然,并没有关于Retrofit的任何依赖,说明我们的Tamic并无投机取巧。
    本次实现只关注Retrofit整体了一个流程思想,其他Retrofit的功能其实就通过以上思想来扩展的,设置解析工厂,返回内容格式,文件上传,下载等,本次实现并没有深入模仿,因为Retrofit整个流程思想比较系统,其他Api和普通Get请求一样,稍微改造一下就可以了。
    与其说是对Retrofit的借鉴,还不如是对Ioc和Aop思想的综合运用。大家也发现本次主要学习依赖注入,和控反转的AOP思想,以及加入代理和接口编程,旨在以后的开发道路上能自我实现一种开发框架,如果感兴趣的同学可以去自我模仿一个RxJava.
    如果你目前项目非常大,网络接口一直以前的httpclient的朋友,可以大但的迁移到Retrofit,只要你稍微做下接口适配,就能很好的让老旧Api接通Retrofit,或者也可以将老Api改造成属于你的Retrofit请求端!领导都无法阻止你用Retrofit的步伐…

    最后感谢淘宝的测试地址:

    URL:"http://ip.taobao.com/service/getIpInfo.php?ip=21.22.11.33";

    源码:
    https://github.com/NeglectedByBoss/Tamic_Retrofit

    相关文章

      网友评论

      • 社会我鹏哥:这个系列的第8篇文章在哪?
        Tamic:@米兰的自由人 http://www.jianshu.com/p/b1979c25634f
      • 叫我丹尼尔:使用前,每次都要初始化一次嘛?设置baseUrl什么的
      • Anderson大码渣:666666666666
      • 河婆墟邓紫棋:跑完项目,回调没有回到主线程,作者本意也是这样么?
        Tamic:@河婆墟邓紫棋 你可以加个handle post到主线程,我的本意是 如果上层是想做数据存储的方面的业务时 主线程又不合适
      • MoTalksCn_林墨:66666
        Tamic:@MoTalksCn_林墨 666
      • 捡淑:66666

      本文标题:Retrofit2.0 源码解析,玩转IOC和AOP, 徒手实现

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