Retrofit源碼分析

1.創(chuàng)建retrofit 對象

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

2.Builder 介紹

  • builder 是用來初始化配置參數(shù)的內(nèi)部類
  • builder 是采用建造者設(shè)計模式
  • 在build() 方法調(diào)用之前必須調(diào)用baseUrl 方法,其他方法都是可選的
builder 成員變量
1. Platform: retrofit 執(zhí)行的的系統(tǒng)環(huán)境偎血,通過findPlatform方法獲取是不是是android環(huán)境
2. okhttp3.Call.Factory :生成請求的工廠類黔衡,默認為okHttpClient
3. baseUrl :HttpUrl 的請求地址
4. List<Converter.Factory> converterFactories:將實體類對象轉(zhuǎn)換成http 傳輸?shù)膶ο蟾浜睿蛘邔ttp 對象轉(zhuǎn)換成實體類對象
5. List<CallAdapter.Factory> adapterFactories :將返回結(jié)果生成指定的類型包裝對象

3.創(chuàng)建請求

//創(chuàng)建api 類
public interface GankApi {
    @GET("data/福利/{number}/{page}")
    Observable<GankBeautyResult> getBeauties(@Path("number") int number, @Path("page") int page);
}

    創(chuàng)建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);
          }
        });
  }
  • 其內(nèi)部使用了動態(tài)代理來實現(xiàn)
ServiceMethod
  • 主要用于處理request 和 response 并將其適配成通過的請求格式
  • 采用了適配器模式,其創(chuàng)建成本很高颓遏,所以retrofit 用一個ConcurrentHashMap serviceMethodCache 來保存,網(wǎng)絡請求需要注意并發(fā)。
   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)
  • 這段代碼主要作用是請求易阳,并返回固定的格式結(jié)果
  @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;
  }

代理模式

靜態(tài)代理

主要思路 代理類持有realsubject 對象,可以對相關(guān)操作進行攔截吃粒。
實例代碼如下:

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("代理人心情不好潦俺, 不安排運動員跑步");
}
}
}
動態(tài)代理

動態(tài)生成對象,可以代理方法

InvocationHandler
  • 產(chǎn)生一個對象的代理對象
  • 代理對象在方法被調(diào)用的時候被觸發(fā)
  • 主要場景:面向切面編程
public class GamePlayIH implements InvocationHandler {
    //被代理者
    Class cls =null;
    //被代理的實例
    Object obj = null;
    //我要代理誰
    public GamePlayIH(Object _obj){
    this.obj = _obj;
}
//調(diào)用被代理的方法
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();
    //動態(tài)產(chǎn)生一個代理者
    IGamePlayer proxy = (IGamePlayer)Proxy.newProxyInstance(cl,new Class[]{GamePlayer.class},handler);
    //登錄
    proxy.login("zhangSan", "password");//開始殺怪
    proxy.killBoss();
    //升級
    proxy.upgrade();
    //記錄結(jié)束游戲時間
    System.out.println("結(jié)束時間是: 2009-8-26 03:40");
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末黑竞,一起剝皮案震驚了整個濱河市捕发,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌很魂,老刑警劉巖扎酷,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異遏匆,居然都是意外死亡法挨,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門幅聘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凡纳,“玉大人,你說我怎么就攤上這事帝蒿〖雒樱” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵葛超,是天一觀的道長暴氏。 經(jīng)常有香客問我,道長绣张,這世上最難降的妖魔是什么答渔? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮侥涵,結(jié)果婚禮上沼撕,老公的妹妹穿的比我還像新娘。我一直安慰自己芜飘,他們只是感情好务豺,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著燃箭,像睡著了一般冲呢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上招狸,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天敬拓,我揣著相機與錄音,去河邊找鬼裙戏。 笑死乘凸,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的累榜。 我是一名探鬼主播营勤,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼灵嫌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了葛作?” 一聲冷哼從身側(cè)響起寿羞,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赂蠢,沒想到半個月后绪穆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡虱岂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年玖院,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片第岖。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡难菌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蔑滓,到底是詐尸還是另有隱情郊酒,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布键袱,位于F島的核電站猎塞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏杠纵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一钩骇、第九天 我趴在偏房一處隱蔽的房頂上張望比藻。 院中可真熱鬧,春花似錦倘屹、人聲如沸银亲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽务蝠。三九已至,卻和暖如春烛缔,著一層夾襖步出監(jiān)牢的瞬間馏段,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工践瓷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留院喜,地道東北人。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓晕翠,卻偏偏與公主長得像喷舀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 簡介 剛接觸Retrofit的時候硫麻,就寫了一篇簡單的使用介紹:Retrofit 2.0基本使用方法,算是對Retr...
    Whyn閱讀 2,844評論 4 24
  • 最近非常流行 Retrofit+RxJava+OkHttp 這一整套的網(wǎng)絡請求和異步操作的開源框架爸邢,從 Jake ...
    慌不要慌閱讀 1,974評論 1 7
  • Retrofit Version:2.2.0分析代碼地址:https://github.com/Blankeer/...
    Blankeer閱讀 223評論 0 1
  • 1.基本使用 參照官方網(wǎng)站實例:(1) 創(chuàng)建一個java接口用來作為http請求 (2) Retrofit類會自動...
    helloKai閱讀 157評論 0 0
  • 一. retrofit的簡單使用 先看下涉及到的類: 首先定義個接口ApiService,所有的請求方法的定義. ...
    小菜_charry閱讀 477評論 0 1