Retrofit源码分析

1.创建retrofit 对象

  Retrofit retrofit = new Retrofit.Builder()
                    .client(okHttpClient)
                    .baseUrl("http://gank.io/api/")
                    .addConverterFactory(gsonConverterFactory)
                    .addCallAdapterFactory(rxJavaCallAdapterFactory)
                    .build();

2.Builder 介绍

  • builder 是用来初始化配置参数的内部类
  • builder 是采用建造者设计模式
  • 在build() 方法调用之前必须调用baseUrl 方法,其他方法都是可选的
builder 成员变量
1. Platform: retrofit 执行的的系统环境,通过findPlatform方法获取是不是是android环境
2. okhttp3.Call.Factory :生成请求的工厂类,默认为okHttpClient
3. baseUrl :HttpUrl 的请求地址
4. List<Converter.Factory> converterFactories:将实体类对象转换成http 传输的对象,或者将http 对象转换成实体类对象
5. List<CallAdapter.Factory> adapterFactories :将返回结果生成指定的类型包装对象

3.创建请求

//创建api 类
public interface GankApi {
    @GET("data/福利/{number}/{page}")
    Observable<GankBeautyResult> getBeauties(@Path("number") int number, @Path("page") int page);
}

    创建api类的请求接口实体类
 retrofit.create(GankApi.class);
create方法介绍:
  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }
  • 其内部使用了动态代理来实现
ServiceMethod
  • 主要用于处理request 和 response 并将其适配成通过的请求格式
  • 采用了适配器模式,其创建成本很高,所以retrofit 用一个ConcurrentHashMap serviceMethodCache 来保存,网络请求需要注意并发。
   ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
  ServiceMethod<?, ?> loadServiceMethod(Method method) {
    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;
  }
serviceMethod.callAdapter.adapt(okHttpCall)
  • 这段代码主要作用是请求,并返回固定的格式结果
  @Override public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

    Observable<?> observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }

    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return observable;
  }

代理模式

静态代理

主要思路 代理类持有realsubject 对象,可以对相关操作进行拦截。
实例代码如下:

public interface IRunner {
//运动员的主要工作就是跑步
public void run();
}

public class Runner implements IRunner {
public void run() {
System.out.println("运动员跑步: 动作很潇洒");
}
}

public class RunnerAgent implements IRunner {
private IRunner runner;
public RunnerAgent(IRunner _runner){
this.runner = _runner;
}/
/代理人是不会跑的
public void run() {
Random rand = new Random();
if(rand.nextBoolean()){
System.out.println("代理人同意安排运动员跑步");
runner.run();
}else{
System.out.println("代理人心情不好, 不安排运动员跑步");
}
}
}
动态代理

动态生成对象,可以代理方法

InvocationHandler
  • 产生一个对象的代理对象
  • 代理对象在方法被调用的时候被触发
  • 主要场景:面向切面编程
public class GamePlayIH implements InvocationHandler {
    //被代理者
    Class cls =null;
    //被代理的实例
    Object obj = null;
    //我要代理谁
    public GamePlayIH(Object _obj){
    this.obj = _obj;
}
//调用被代理的方法
public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
    Object result = method.invoke(this.obj, args);
    return result;
    }
}

public class Client {
public static void main(String[] args) throws Throwable {
    //定义一个痴迷的玩家
    IGamePlayer player = new GamePlayer("张三");
    //定义一个handler
    InvocationHandler handler = new GamePlayIH(player);
    //开始打游戏, 记下时间戳
    System.out.println("开始时间是: 2009-8-25 10:45");
    //获得类的class loader
    ClassLoader cl = player.getClass().getClassLoader();
    //动态产生一个代理者
    IGamePlayer proxy = (IGamePlayer)Proxy.newProxyInstance(cl,new Class[]{GamePlayer.class},handler);
    //登录
    proxy.login("zhangSan", "password");//开始杀怪
    proxy.killBoss();
    //升级
    proxy.upgrade();
    //记录结束游戏时间
    System.out.println("结束时间是: 2009-8-26 03:40");
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容