android中Retrofit2源碼解析(新版本)

android中Retrofit源碼解析(新版)

在android開發(fā)中我們原生應(yīng)用發(fā)起網(wǎng)絡(luò)請求的時(shí)候杯拐,不免需要使用android對網(wǎng)絡(luò)請求的封裝,它提供了對http協(xié)議底層的抽象错森,我們可以通過它提供的方法直接調(diào)用http請求。在android2.2版本及其以前的版本使用HttpClient,在android2.3版本及其之后我們使用了httpUrlConnection翘瓮,而且在6.0之后android移除了httpClient箱舞,我們在高版本的API中只能使用HttpUrlConnection了遍坟。

1.1 retrofit和OkHttp的關(guān)系

但是實(shí)際情況是使用了httpUrlConnection還是很繁瑣,我們還是要去考慮超時(shí)時(shí)間晴股,服務(wù)器異常情況愿伴、數(shù)據(jù)流轉(zhuǎn)為實(shí)體對象這些煩惱。所以有了對android內(nèi)置的HttpUrlConnection or httpClient的包裝电湘,讓我們專心處理業(yè)務(wù)邏輯隔节。oKHttp就誕生了,android4.4版本以后都內(nèi)置了oKHttp了寂呛,而我們要討論的retrofit就是再次對okHttp的包裝怎诫,豐富了很多強(qiáng)大的功能,比如能和Rxjava這個(gè)流行的框架結(jié)合贷痪,返回結(jié)果能回調(diào)到UI線程等幻妓。oKHttp的源碼涉及到了對阻塞隊(duì)列,線程池的應(yīng)用呢诬,我們下一節(jié)進(jìn)行探討涌哲。

1.2 retrofit的本質(zhì)

retrofit的本質(zhì)就是應(yīng)用了大量的設(shè)計(jì)模式對Okhttp進(jìn)行了封裝,加入了網(wǎng)絡(luò)數(shù)據(jù)轉(zhuǎn)換尚镰、網(wǎng)絡(luò)請求回調(diào)阀圾、網(wǎng)絡(luò)請求適配這幾個(gè)主要的功能。它本身肯定不會去發(fā)請求的狗唉,發(fā)請求交給了OkHttp初烘,它只對調(diào)用方式和返回結(jié)果進(jìn)行處理其他的不關(guān)它的事。為什么要去研究retrofit的源碼呢分俯?因?yàn)樗庋b的方式解耦性很高肾筐,功能調(diào)用十分簡潔,可以參照它對我們的代碼也能進(jìn)行改造缸剪。

1.3 源碼解析(retrofit:2.4.0)

1.3.1 retrofit的創(chuàng)建

一起打開IDE閱讀源碼更虛嘎痤怼!retrofit的創(chuàng)建是整個(gè)框架的入口杏节,它肯定會提前準(zhǔn)備好很多看不懂的變量進(jìn)行初始化唬渗,但是這不能阻擋我們典阵,往后看就能理解它代表的含義了。根據(jù)官方的文檔镊逝,retrofit的創(chuàng)建使用了建造者模式壮啊。

Retrofit retrofit = new Retrofit.Builder() 
//基本URL
.baseUrl("https://www.baidu.com") 
//網(wǎng)絡(luò)請求適配器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
//網(wǎng)絡(luò)請求數(shù)據(jù)轉(zhuǎn)換器
.addConverterFactory(GsonConverterFactory.create()) 
//網(wǎng)絡(luò)請求執(zhí)行器
.client(new OkHttpClient())       
.build(); 

所謂建造者模式就是有builder關(guān)鍵字的方式,就是這么簡單撑蒜!當(dāng)然這是一個(gè)玩喜歹啼,建造者模式和我們以前 get/set 類的屬性沒有什么本質(zhì)的區(qū)別,主要是將這些set方法全部提取出來 形成一個(gè)抽象類或者內(nèi)部類座菠,然后在一個(gè)建造者類里面去設(shè)置屬性狸眼,返回一個(gè)實(shí)體類對象,列如:

public abstract Builder{
public void BulidProperty(String url);
}
public class RealBuilder extends Builder{
private RealObject object;
public void BulidProperty(String url){
    object.SetProperty(url);
     }
 public RealObject build(){
     return RealObject;
     }
}

簡單的思想大概是這樣的辈灼,具體的我們可以看一下Retrofit中的源碼份企。第一行代碼

//第一行代碼
Retrofit retrofit = new Retrofit.Builder() 

很明顯這個(gè)Builder是一個(gè)Retrofit的內(nèi)部類,那說明建造者不是繼承了抽象類巡莹,而是使用了內(nèi)部類來設(shè)置屬性司志。來看一下這個(gè)內(nèi)部類,如下:


public static final class Builder { 
    //不知道這是什么東東先放在一邊
    private final Platform platform;
    //很明顯出現(xiàn)了okhttp降宅,就知道它肯定負(fù)責(zé)去發(fā)請求
    private okhttp3.Call.Factory callFactory;  
    // 8必多說 大家都懂
    private HttpUrl baseUrl;
    //很明顯它是存數(shù)據(jù)轉(zhuǎn)換用的骂远,但是為什么搞一個(gè)list 懵b?
    private final List<Converter.Factory> converterFactories = new ArrayList<>(); 
    //很明顯它存網(wǎng)絡(luò)適配器用的腰根,再次疑問這個(gè)網(wǎng)絡(luò)適配器是什么東東激才?
    private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>(); 
    //很明顯他是一個(gè)回調(diào)執(zhí)行器,這個(gè)有什么用呢额嘿?
    private Executor callbackExecutor; 
    //這肯定是校驗(yàn)Flag目前不知道有什么用
    private boolean validateEagerly;

里面看不懂的變量主要有adapterFactories存的網(wǎng)絡(luò)適配器工廠(CallAdapter.Factory)瘸恼,很明顯他后面會使用工廠設(shè)計(jì)模式去產(chǎn)生CallAdapter的對象祠肥,至于數(shù)據(jù)轉(zhuǎn)換器(converter)我們都知道http請求返回來的是數(shù)據(jù)流InputStream方式的时捌,轉(zhuǎn)為Json,XML之類需要一個(gè)轉(zhuǎn)換器巩踏,類似于一個(gè)double轉(zhuǎn)int的工具類球拦。

  • 網(wǎng)絡(luò)適配器的含義及其作用:網(wǎng)絡(luò)適配器是我自己給他的定義靠闭,從命名上來看是叫:CallAdapter,Call肯定是來發(fā)請求的坎炼,Adapter憶往昔崢嶸歲月愧膀,在listView里面是界面和數(shù)據(jù)的橋梁,同理這里的CallAdapter應(yīng)該是客戶端和網(wǎng)絡(luò)之間橋梁谣光¢萘埽客戶端發(fā)請求的操作肯定是要通過它的。如圖:
image.png

這樣我們就可以清楚的看到了CallAdapter的作用了萄金,它對OkHttp進(jìn)行包裝狼钮,我們調(diào)用請求方法的時(shí)候都要通過它碳柱。它同時(shí)持有了okHttp對象和回調(diào)執(zhí)行器的對象,這樣它通過Okhttp拿到數(shù)據(jù)之后熬芜,用回調(diào)執(zhí)行器回調(diào)。

  • 回調(diào)執(zhí)行器:回調(diào)執(zhí)行器就是在拿到數(shù)據(jù)結(jié)果之后福稳,我們怎么返回結(jié)果的問題涎拉,主要的問題就是由于是異步請求,我們想要使用數(shù)據(jù)填充界面的圆,需要切換到主線程鼓拧。
  //再看看構(gòu)造函數(shù)
  Retrofit retrofit = new Retrofit.Builder() 

這個(gè)內(nèi)部類的構(gòu)造函數(shù)做了些什么內(nèi)容?就一句調(diào)用自己的有參構(gòu)造函數(shù)越妈,佛了季俩!

public Builder() {  this(Platform.get());}

我們來看看這個(gè)有參構(gòu)造函數(shù)和Platform類是什么東東:

    //Platform類
class Platform {
  private static final Platform PLATFORM = findPlatform();
  static Platform get() {
  //f返回一個(gè)實(shí)例就完事了
    return PLATFORM;
  }
  //根據(jù)不同運(yùn)行平臺返回對應(yīng)的Platforem對象 
     private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

看到這里我們就明白了,他根據(jù)運(yùn)行的平臺不同來返回相應(yīng)的對象梅掠,我們這里只分析 new Adnroid();看看里面有什么內(nèi)容:

static class Android extends Platform {
 //一個(gè)默認(rèn)的回調(diào)執(zhí)行器
    @Override
     public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
    //很明顯 很熟悉 酌住!創(chuàng)建了一個(gè)默認(rèn)的CallAdapter(網(wǎng)絡(luò)適配器),而且傳入了一個(gè)回調(diào)執(zhí)行器(回調(diào)執(zhí)行器可以自定義阎抒,不然就是用默認(rèn)綁定主線程)
    @Override 
    CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
     static class MainThreadExecutor implements Executor {
     //給力 綁定了主線程的 looper (關(guān)于Handler的詳細(xì)內(nèi)容可以自己查詢)
      private final Handler handler = new Handler(Looper.getMainLooper());
      @Override 
      public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

到此我們明白了 Platfrom的作用了酪我,它提供了一個(gè)默認(rèn)的CallAdapter.Factory用來生產(chǎn)CallAdapter,還提供了一個(gè)綁定主線程的默認(rèn)回調(diào)執(zhí)行器且叁。

再次回頭看創(chuàng)建Retrofit的其他代碼

Retrofit retrofit = new Retrofit.Builder() 
//基本URL
.baseUrl("https://www.baidu.com")
//可以自定義回調(diào)執(zhí)行器都哭,否則默認(rèn)回調(diào)到主線程
.callbackExecutor("xxxx")
//網(wǎng)絡(luò)請求適配器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
//網(wǎng)絡(luò)請求數(shù)據(jù)轉(zhuǎn)換器
.addConverterFactory(GsonConverterFactory.create()) 
//網(wǎng)絡(luò)請求執(zhí)行器
.client(new OkHttpClient())       
.build(); 

baseUrl、add這些方法是給內(nèi)部類屬性賦值逞带,我們主要來看build()方法欺矫。

 public Retrofit build() {
    //可見baseUrl 是必須的 使用的時(shí)候要注意
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //很明顯 生產(chǎn)網(wǎng)絡(luò)請求的工廠,如果你不傳入自定義的okHttp對象展氓,他會默認(rèn)使用okHttpclient
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      //如果沒有自定義穆趴,加入剛剛說過的默認(rèn)調(diào)到到主線程
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
      //將傳入到內(nèi)部類callAdapter copy一份 傳入到retrofit的構(gòu)造函數(shù)
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
        //它會添加一個(gè)默認(rèn)的網(wǎng)絡(luò)適配器,這個(gè)網(wǎng)絡(luò)適配器它持有callbackExecutor回調(diào)執(zhí)行器的對象带饱。
      callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
      //很明顯類似adapterFactories 添加了一個(gè)默認(rèn)毡代,再copy一份到 retrofit的構(gòu)造函數(shù)中。
      List<Converter.Factory> converterFactories =new ArrayList<>(1 + this.converterFactories.size());
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      //返回retrofit的實(shí)例對象就完事了
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
  }

這里的代碼都很簡單勺疼,但是有幾個(gè)疑問教寂?為什么這個(gè)adapterFactories和converterFactories都是list呢,它里面都存了些什么执庐。

  • adapterFactories: 一個(gè)list集合酪耕,存儲了網(wǎng)絡(luò)適配器工廠,根據(jù)上面的代碼我們可以看到它里面的內(nèi)容是:先添加了自定義的轨淌、后面添加了一個(gè)默認(rèn)的迂烁,總共兩個(gè)元素看尼。在Retrofit中提供了四種CallAdapterFactory: ExecutorCallAdapterFactory(默認(rèn))、GuavaCallAdapterFactory盟步、Java8CallAdapterFactory藏斩、RxJavaCallAdapterFactory。其他的沒有用過却盘,但是看到Rxjava我們就知道了狰域,如果想要和Rxjava結(jié)合起來這個(gè)RxJavaCallAdapterFactory必須添加進(jìn)去
//通過這個(gè)添加進(jìn)去,是不是可以添加多個(gè)呢黄橘?
Retrofit retrofit = new Retrofit.Builder() 
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
//我們還可以添加
// adapterFactories里面順序
// 自定義1-自定義2-.....默認(rèn)兆览。
addCallAdapterFactory(Java8CallAdapterFactory.create())
addCallAdapterFactory(GuavaCallAdapterFactory.create())
//converter 同理啊鐵子!
.addConverterFactory(GsonConverterFactory.create()) 

也不會有問題塞关,因?yàn)槲覀兙W(wǎng)絡(luò)請求都是多種多樣的抬探,上面已經(jīng)說得我們發(fā)請求就是操作CallAdapter,所以有結(jié)果返回的時(shí)候也需要通過CallAdapter帆赢。有時(shí)候我們需要Rxjava的observeable這種返回對象小压,有時(shí)候我們還是需要Call這種類型的返回對象,所以他需要一個(gè)list去組裝對應(yīng)的CalladapterFactory匿醒,Call代表了默認(rèn)CallAapter返回出來的的场航,Observable代表了我們添加進(jìn)去的RxJavaCallAdapter返回出來的。同理我們需要從CallAdapter得到想要的數(shù)據(jù)類型廉羔,converterFactories也需要多個(gè)溉痢。

    @GET
    //我想要Observable 需要相應(yīng)的的CallAdapter
   Observable<ResponseBody> download(@Url String url);
    @GET
        //我想要Call 默認(rèn)的CallAdapter就行
        //同時(shí)還需要將結(jié)果變成IModel 怎么說吧你
    Call<IModel>download(@Url String url);

總結(jié):我們清楚的看到了,retrofit的創(chuàng)建過程憋他,主要的內(nèi)容就是四個(gè)器的初始化孩饼,網(wǎng)絡(luò)適配器(CallAdapter),數(shù)據(jù)轉(zhuǎn)換器(conver)竹挡,請求執(zhí)行器(oKHttp)镀娶,回調(diào)執(zhí)行器(callbackExecutor)。關(guān)注點(diǎn)在我們發(fā)請求操作都是CallAdapter揪罕,它肯定持有其他三個(gè)的引用梯码,就像吃雞里面他是我們的角色,其他的是M4,頭盔 藥品等好啰。

1.3.2 創(chuàng)建網(wǎng)絡(luò)請求接口的實(shí)例轩娶。

對我們的的注解定義的接口方法進(jìn)行解析,從而創(chuàng)建實(shí)例框往,有點(diǎn)迷惑鳄抒?什么實(shí)例,干什么用的?我們繼續(xù)往下看许溅。

retrofit.create(RetrofitService.class);

看到這種傳入.class的 瓤鼻,我們可以想到肯定會用到反射。

 public <T> T create(final Class<T> service) {
    //校驗(yàn)接口正確性贤重,是否符合注解規(guī)則
    Utils.validateServiceInterface(service);
    //validateEagerly 這個(gè)變量主要是作用是 是否提前加入緩存
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //很明顯這里使用了動態(tài)代理模式
    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 {
              //如果是java里面的基類不做處理 
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            // 這個(gè)沒什么用android平臺默認(rèn)返回的是false的
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
           //非常重要的3行代碼
           //解析方法的返回參數(shù) 請求參數(shù) 請求類型等
            ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
            //很明顯OkHttp就知道他是一個(gè)網(wǎng)絡(luò)執(zhí)行器
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            //很明顯他 肯定是調(diào)用了callAdapter  
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

這里的代碼稍微有一丟丟復(fù)雜茬祷,主要理解代理模式。代理代理并蝗,不知道大家是否知道代購牲迫。比如你想買一件surpene的衣服,當(dāng)然superme肯定買不起借卧,只能買買faker。又拉下不臉筛峭,找了一個(gè)代購铐刘。

image.png

代理類會獲取被代理類的所有方法,并返回一個(gè)被代理類的對象影晓,這個(gè)對象就是虛擬的你镰吵,通過它去購買需要的商品。Proxy.newProxyInstance(xxx)是固定用法挂签,只要傳入xxx.class參數(shù)就行疤祭。

     //固定格式
     ClassLoader classLoader =Shop.class.getClassLoader();
     //固定格式,三個(gè)參數(shù)饵婆,傳入Shop.class參數(shù)勺馆,獲取所有方法,返回代理對象侨核。
     Shop shopProy = (Shop) Proxy.newProxyInstance(classLoader, new Class[]{IShop.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //回調(diào)原來類的方法草穆,該怎么做就怎么做
                Object result = method.invoke(proxy,args);
                //也可以自己實(shí)現(xiàn) 不回調(diào)原來的方法。
                //.............................
                return result;
            }
        });

這里的Invoke方法搓译,就是代理方法的實(shí)現(xiàn)悲柱,method.invoke()代表了回調(diào)原來的方法,這里也可以自己去實(shí)現(xiàn)方法些己,只要返回對應(yīng)的類型豌鸡。代理模式優(yōu)點(diǎn)就是提供了一個(gè)攔截接口,不管你什么方法調(diào)用都會先進(jìn)入Invoke段标。具體內(nèi)容可以學(xué)習(xí)JAVA反射來加深印象涯冠。

  .........................................
  //validateEagerly 這個(gè)變量主要是作用是 是否提前加入緩存
   if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //很明顯這里使用了動態(tài)代理模式
    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 {
              //.............................
           //非常重要的3行代碼
           //解析方法的返回參數(shù) 請求參數(shù) 請求類型等 關(guān)鍵代碼1
            ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
            //很明顯OkHttp就知道他是一個(gè)網(wǎng)絡(luò)執(zhí)行器 關(guān)鍵代碼2
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            //很明顯他 肯定是調(diào)用了callAdapter   關(guān)鍵代碼3
            return serviceMethod.adapt(okHttpCall);
            }

回到代理創(chuàng)建接口實(shí)例的方法中,我們創(chuàng)建接口的時(shí)候都是只寫了方法名怀樟,沒有具體的實(shí)現(xiàn)功偿,所以在代理對象并不能回調(diào),它只能自己去實(shí)現(xiàn)而且還要返回你要想的結(jié)果類型⌒岛桑苦b肮菜!!

public interface RetrofitService {
  //沒有方法體 只有名字 怎么破(只能靠retrofit給我們實(shí)行)
   @GET
  Observable<ResponseBody> download(@Url String url);
   // 沒有方法體吨瞎,只有名字 怎么破
   @GET
   Call<ResponseBody>download(@Url String url);
}

在retrofi中痹兜,利用了ServceMehod這個(gè)類來進(jìn)行實(shí)現(xiàn)方法體,它會獲取到接口方法的參數(shù)颤诀,返回值類型字旭,請求方式等所有參數(shù)⊙陆校看一下關(guān)鍵代碼1遗淳,loadServiceMethod()!心傀!

 ServiceMethod<?, ?> loadServiceMethod(Method method) {
   //搞個(gè)緩存啊 美滋滋
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
      //緩存里面沒有,說明是第一次調(diào)用屈暗,安排一下,并且加入緩存
        result = new ServiceMethod.Builder<>(this, method).build();//我只是一個(gè)建造者脂男,傳入了retrofit的對象养叛,擁有了adapterFactorese等所有屬性。
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

代碼很簡單宰翅,對調(diào)用的方法做一個(gè)緩存弃甥,第一次調(diào)用的時(shí)候才會去解析方法,其他情況下會使用緩存汁讼。同時(shí)我們也應(yīng)該知道validateEagerly這個(gè)Flag的作用了淆攻,如果你設(shè)置為true會創(chuàng)建動態(tài)代理對象的時(shí)候?qū)⑺械姆椒ń馕鼍彺妫駝t就只會在第一次調(diào)用的時(shí)候去緩存掉缺。
雖然已經(jīng)知道了ServiceMethod會對我們請求的方法進(jìn)行一頓瞎x操作卜录,各種解析分析組裝,但是我們還要要去看看實(shí)況眶明,它采用了建造者模式(builder)艰毒,直接看.build()方法。

 public ServiceMethod build() {
     ..........................................//
     //根據(jù)返回值類型搜囱,在adapterFactories的list里面去尋找CallAdapter丑瞧,如observeable,就會尋找RxjavCallAdapter.Factory 工廠模式產(chǎn)生CallAdapter 的對象蜀肘。
      callAdapter = createCallAdapter();
      //獲取返回值中的數(shù)據(jù)類型
      responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      //根據(jù)CallAdapter的返回的值中的數(shù)據(jù)類型(如: Call<Bean> download()绊汹, 就會根據(jù) ‘ Bean’去尋找Gson轉(zhuǎn)換器)去遍歷converterList找轉(zhuǎn)換器,Converter 的對象扮宠。
      responseConverter = createResponseConverter();
      //遍歷方法中的所有注解 一頓操作保存起來西乖。
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      int parameterCount = parameterAnnotationsArray.length;
      // 保存請求參數(shù)的工具類
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        ..................///
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        ..................//
        //遍歷方法參數(shù)中的所有注解和變量到parameterHandlers
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
      .......................//
      //返回一個(gè) ServiceMethod的實(shí)例
      return new ServiceMethod<>(this);
    }

主要作用是根據(jù)方法的返回值類型,獲取相應(yīng)的網(wǎng)絡(luò)適配器、數(shù)據(jù)轉(zhuǎn)換器以及拆卸參數(shù)類型等保存在parameterHandlers中获雕。列如:createCallAdapter會去遍歷callAdapterFactories找到相應(yīng)的callAdapter薄腻。

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
      //.......................................................
      //根據(jù)返回值遍歷callAdapterFactories
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
     // get返回了一個(gè)CallAdapter對象
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
    
    //這里假設(shè)我們返回值是 Call<Bean> 類型的 ,默認(rèn)的ExecutorCallAdapterFactory會被匹配到届案♀挚看看它的get方法
  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    //給力呀 鐵子 返回了一個(gè) CallAdapter對象
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }
      // 我就是方法體啊鐵子 
      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

其中Calladapter中的adapt方法就是方法體了。后續(xù)詳細(xì)介紹這個(gè)CallAdapter類楣颠。
根據(jù)關(guān)鍵代碼1, loadServiceMethod()返回了一個(gè)ServiceMethod的實(shí)例尽纽,它里面包含了你調(diào)用方法的所有信息,包含注解童漩,參數(shù)類型弄贿,參數(shù)名,返回值類型等矫膨,來看看它里面主要的屬性:

  final class ServiceMethod<R, T> {
   .............................//
  //這個(gè)是Okhttp的工廠實(shí)例挎春,用來生產(chǎn)請求call的
  private final okhttp3.Call.Factory callFactory;
  //橋梁callAdapter 實(shí)例 發(fā)請求都是它在操作okhttp
  private final CallAdapter<R, T> callAdapter;
  // 8 必再說
  private final HttpUrl baseUrl;
  //數(shù)據(jù)轉(zhuǎn)換器實(shí)例
  private final Converter<ResponseBody, R> responseConverter;
.......................//
//存儲請求參數(shù)的集合
  private final ParameterHandler<?>[] parameterHandlers;

到此Retrofi已經(jīng)實(shí)現(xiàn)了高度的解耦,定義一個(gè)請求方法豆拨,我只想調(diào)用一下得到結(jié)果,至于怎么請求的能庆,和怎么轉(zhuǎn)換結(jié)果都不想關(guān)注施禾。retrofit在這里使用了外觀模式,只用定義方法入口(Retrofit.create(YourInterface.Class))搁胆,減少了對內(nèi)部細(xì)節(jié)的依賴弥搞,里面發(fā)生了變化,我們也不用擔(dān)心渠旁。
繼續(xù)看關(guān)鍵代碼2:

//很明顯這里使用了動態(tài)代理模式
    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 {
              //.............................
           //非常重要的3行代碼
           //解析方法的返回參數(shù) 請求參數(shù) 請求類型等 關(guān)鍵代碼1
            ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
            //很明顯OkHttp就知道他是一個(gè)網(wǎng)絡(luò)執(zhí)行器 關(guān)鍵代碼2
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            //很明顯他 肯定是調(diào)用了callAdapter   關(guān)鍵代碼3
            return serviceMethod.adapt(okHttpCall);
            }

將servcieMethod傳入到oKhttpCall攀例,serviceMethod已經(jīng)把請求參數(shù)拆卸下來存儲在了parameterHandlers中,OkHttpCall會取出參數(shù)類型和值進(jìn)行組裝請求顾腊。

final class OkHttpCall<T> implements Call<T> {
  private final ServiceMethod<T, ?> serviceMethod;//含有所有網(wǎng)絡(luò)請求參數(shù)類型等等
  private final @Nullable Object[] args;//請求參數(shù)的值

  private volatile boolean canceled;//取消請求Falg

  @GuardedBy("this")
  private @Nullable okhttp3.Call rawCall;//真正發(fā)請求的Okhttp
............................................//

  }

OkHttpCall里面有了okhttp對象粤铭,使用它來進(jìn)行發(fā)請求操作,具體我們往下看杂靶。
關(guān)鍵代碼3:

        //很明顯他 肯定是調(diào)用了callAdapter   關(guān)鍵代碼3
            return serviceMethod.adapt(okHttpCall);
    // 在ServiceMethod中adapt 調(diào)用了callAdapter
    final class ServiceMethod {
    ..................................//
      T adapt(Call<R> call) {
          return callAdapter.adapt(call);
        }
   ...............................//     
     }      

將生產(chǎn)好的Call對象傳入到adapter中梆惯,然后開始實(shí)現(xiàn)方法體.
這里結(jié)合實(shí)例來看:

    //我想要Call類型的返回值,使用默認(rèn)CallAdapter的就行了
    @GET
    Call<Model>download(@Url String url);
    
    //使用 mRetrofitService.downloadADfile(xxx),就是在調(diào)用  serviceMethod.adapt(okHttpCall);
    Call<Model> call = mRetrofitService.downloadADfile("www.kawayi.com");   

我們在這里的 "call = "返回的是什么呢吗垮?來看一哈肯定很簡單垛吗。

//根據(jù)剛返回類型'Call' 遍歷CallAdapterFactories循環(huán)出得到默認(rèn)CallAdapter
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }
      //返回了一個(gè)ExecutorCallbackCall對象 來看一哈
      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

很顯然返回了一個(gè)ExecutorCallbackCall對象,ExecutorCallbackCall內(nèi)容并不是很復(fù)雜烁登。

//這里是ExecutorCallbackCall 繼承了Call
static final class ExecutorCallbackCall<T> implements Call<T> {
  //回調(diào)執(zhí)行器怯屉,有自定義就用自定義否則就會使用platform這個(gè)對象生產(chǎn)出綁定主線程的回調(diào)
  final Executor callbackExecutor;
  //這里傳入的是OkhttpCall
  final Call<T> delegate;
  //構(gòu)造函數(shù),傳入了OkhttpCall,和回調(diào)執(zhí)行器锨络,裝飾模式安排安排
  ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
    this.callbackExecutor = callbackExecutor;
    this.delegate = delegate;
  }
  //執(zhí)行異步請求
  @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");
    delegate.enqueue(new Callback<T>() {
      @Override public void onResponse(Call<T> call, final Response<T> response) {
          //回調(diào)執(zhí)行器 切換線程
        callbackExecutor.execute(new Runnable() {
          @Override public void run() {
            if (delegate.isCanceled()) {
              callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
            } else {
              callback.onResponse(ExecutorCallbackCall.this, response);
            }
          }
        });
      }
     .......................//
}

代碼很簡單赌躺,顯然CallAdapter的內(nèi)部類ExecutorCallbackCall擁有okhttp和回調(diào)執(zhí)行器,所有的一切操作都在是它在執(zhí)行了足删。這里使用了裝飾模式寿谴,加強(qiáng)了okhttCall。裝飾模式:就是不改變類文件和使用繼承的情況下失受,動態(tài)地?cái)U(kuò)展一個(gè)對象的功能讶泰,是一種代替繼承的方案。


image.png

C和A都繼承了B拂到,但C里面有A的對象痪署,所以他可以調(diào)用A的方法,而且能添加一些A中沒有的功能兄旬。如:

  
  static final class ExecutorCallbackCall<T> implements Call<T> {
   ......................................//
    //ExeCutorCallbackCall和delegate都繼承了Call狼犯,但ExeCutorCallbackCall有回調(diào)執(zhí)行,取消請求這些功能领铐,得到了加強(qiáng)悯森。
    final Call<T> delegate;

這里的delegate得到了加強(qiáng),擁有了切換線程的功能绪撵。

總結(jié):retrofit.create(RetrofitService.class)瓢姻,使用了動態(tài)代理創(chuàng)建RetrofitService對象,并且對它接口中的方法進(jìn)行了實(shí)現(xiàn)音诈,根據(jù)返回值的類型幻碱,尋找CallAdapter和converter并且拆卸請求參數(shù),組裝請求细溅,最后返回了Call的對象褥傍。

1.3.3 返回值執(zhí)行網(wǎng)絡(luò)請求

根據(jù)實(shí)例來看源碼:


//我想要Call類型的返回值,使用默認(rèn)CallAdapter的就行了 
@GET Call<Model>download(@Url String url); 
//實(shí)際上就是在調(diào)用serviceMethod.adapt(okHttpCall); 
Call<Model> call = mRetrofitService.downloadADfile("www.kawayi.com");
//發(fā)一個(gè)異步請求喇聊。
 call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {

            }
            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
            }
   });

根據(jù)剛剛分析的代碼可以知道恍风,返回的call對象是ExecutorCallbackCall的實(shí)例,enque執(zhí)行異步請求的誓篱,就會調(diào)用ExecutorCallbackCall的enque方法邻耕。

//這里是ExecutorCallbackCall 繼承了Call
static final class ExecutorCallbackCall<T> implements Call<T> {
  //執(zhí)行異步請求
  @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");
    //okhttpCall去執(zhí)行請求,奧給力燕鸽。
    delegate.enqueue(new Callback<T>() {
      @Override public void onResponse(Call<T> call, final Response<T> response) { 
      //這只是一個(gè)回調(diào)執(zhí)行器兄世,切換線程
        callbackExecutor.execute(new Runnable() {
          @Override public void run() {
            if (delegate.isCanceled()) {
              callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
            } else {
              callback.onResponse(ExecutorCallbackCall.this, response);
            }
          }
        });
      }
     .......................//
}

代碼中可以看到,我們傳入的okHttpCall(serviceMethod.adapt(okHttpCall))會調(diào)用okttp去執(zhí)行請求啊研,并且用回調(diào)執(zhí)行器回調(diào)okhttp返回的數(shù)據(jù)數(shù)據(jù)御滩。
下面來看看okHttp具體是怎么處理的

 final class OkHttpCall<T> implements Call<T> {
  private final ServiceMethod<T, ?> serviceMethod;//含有所有網(wǎng)絡(luò)請求參數(shù)類型等等
  @GuardedBy("this")
  private @Nullable okhttp3.Call rawCall;//真正發(fā)請求的Okhttp
............................................//
  //發(fā)一個(gè)異步請求鸥拧。實(shí)際上是okhttp操作
 @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");
    //okhttp的實(shí)例
    okhttp3.Call call;
    ..............................................\\
   call = rawCall = createRawCall() ;//拿到parameterHandlers的參數(shù)削解,組裝一個(gè)請求   
   ...........................................\\
   //真正的發(fā)一個(gè)請求
  call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
        //使用數(shù)據(jù)轉(zhuǎn)換器富弦,轉(zhuǎn)換一下就完事了。
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
         try {
         //回到到對應(yīng)的CallbackCall中氛驮,默認(rèn)是ExecutorCallbackCall
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
        
        

OkhttpCall首先先對請求進(jìn)行一個(gè)組裝腕柜,然后賦值給一個(gè)okhttp.Call的對象。通過call對象去發(fā)起請求矫废,中間有異常超時(shí)對應(yīng)的處理盏缤,拿到正確的請求結(jié)果之后,解析數(shù)據(jù)蓖扑,回調(diào)到對應(yīng)的CallbackCall唉铜,默認(rèn)是ExecutorCallbackCall,最后在ExecutorCallbackCall中使用回調(diào)執(zhí)行器再次回調(diào)律杠。

2.1 總結(jié)

1潭流、Retrofit對oKHttp層層封裝,利用動態(tài)代理模式柜去,實(shí)現(xiàn)接口定義的方法灰嫉。
2、根據(jù)返回值類型匹配對應(yīng)的CallAdapter嗓奢,converter熬甫,這里使用了策略模式。在對應(yīng)的callAdapter中使用了裝飾器模式并且返回了一個(gè)加強(qiáng)的Call對象蔓罚。
3、利用返回的Call對象來發(fā)請求瞻颂,利用內(nèi)部包裝的OkHttp對象豺谈,執(zhí)行請求。結(jié)果返回之后贡这,converter解析數(shù)據(jù)茬末,經(jīng)過層層回調(diào),到最后回調(diào)執(zhí)行器切換線程盖矫。

參考文獻(xiàn)
[1]劉望舒.Android進(jìn)階之光

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末丽惭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子辈双,更是在濱河造成了極大的恐慌责掏,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件湃望,死亡現(xiàn)場離奇詭異换衬,居然都是意外死亡痰驱,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門瞳浦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來担映,“玉大人,你說我怎么就攤上這事叫潦∮辏” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵矗蕊,是天一觀的道長短蜕。 經(jīng)常有香客問我,道長拔妥,這世上最難降的妖魔是什么忿危? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮没龙,結(jié)果婚禮上铺厨,老公的妹妹穿的比我還像新娘。我一直安慰自己硬纤,他們只是感情好解滓,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著筝家,像睡著了一般洼裤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上溪王,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天腮鞍,我揣著相機(jī)與錄音,去河邊找鬼莹菱。 笑死移国,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的道伟。 我是一名探鬼主播迹缀,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蜜徽!你這毒婦竟也來了祝懂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤拘鞋,失蹤者是張志新(化名)和其女友劉穎砚蓬,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盆色,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怜械,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年颅和,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缕允。...
    茶點(diǎn)故事閱讀 38,789評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡峡扩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出障本,到底是詐尸還是另有隱情教届,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布驾霜,位于F島的核電站案训,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏粪糙。R本人自食惡果不足惜强霎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蓉冈。 院中可真熱鬧城舞,春花似錦、人聲如沸寞酿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伐弹。三九已至拉馋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惨好,已是汗流浹背煌茴。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留日川,地道東北人蔓腐。 一個(gè)月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像逗鸣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子绰精,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評論 2 351

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

  • ??今天我來記錄一下我對Retrofit框架的理解撒璧。不得不說,Retrofit的架構(gòu)設(shè)計(jì)極其優(yōu)秀笨使,既保證了使用上的...
    瓊珶和予閱讀 3,829評論 0 21
  • 適配器模式上一篇文章我們已經(jīng)分析了Retrofit解析注解封裝進(jìn)ServiceMethod的流程卿樱,讀者在這里要記住...
    andcoder閱讀 648評論 0 2
  • 目錄介紹 1.首先回顧Retrofit簡單使用方法 2.Retrofit的創(chuàng)建流程源碼分析2.1 Retrofit...
    楊充211閱讀 1,051評論 0 16
  • 花間辭 作者/陳海洲 迎春之花 陽光還不夠溫暖,會有鮮艷的色彩為我們?nèi)∨?會有一些驚喜打破荒蕪 寒意還未退去硫椰,在這...
    陳海洲洹河閱讀 437評論 0 2
  • 狂風(fēng)忽云雨繁调,夜半驚坐起萨蚕! 醒來殘?jiān)冢瑵M地是狼藉蹄胰。
    如魚得水1994閱讀 199評論 0 0