Android 經常使用開源框架源碼解析 系列 (三)網絡框架之一 Retrofit

Retrofit
 
1、定義
 對OkHttp網絡請求框架的封裝 !不是一個網絡請求框架
 
2、概述
A type-safe HTTP client for Android and Java
將每個Http api請求轉換成Java接口,專一於接口層的封裝工做
 
Retrofit是一個RestFul Http ,對底層網絡請求框架的封裝,完成各種數據的轉換和適配工做
 
  • App經過Retrofit 請求網絡,實際上說使用Retrofit接口層封裝請求參數,以後由OkHttp完成後續實際請求操做
  • 在服務端返回數據以後,OkHttp將原始的結果交給Retrofit,Retrofit根據用戶的需求對結構進行解析
 
3、流程
 
Retrofit——門戶類,入口類  ,配置網絡請求參數
    |
    |
ServiceMethod——對應本身建立接口類裏方法,經過動態代理模式,接口中方法轉換成Http請求;
                                 解析方法中的註解,生成Request對象等內容;
    |
    |
    |
        ——— CallAdapter工廠——生產網絡請求的Call適配器,默認封裝成OkHttpCall;
    |                                                將OHC轉換成適合不一樣平臺使用的網絡請求的模式
    |
    |
        ——— Converter工廠 ——生產數據轉換器Converter;Response轉換成能夠識別的Java對象 
    |
    |
    |
        ————Call工廠——生產實際Call請求;Http請求都會被封裝成Call類,
    |                                                         Http請求表示都是已經準備好隨時可運行的請求
    |
    |
   V
    ———— OkHttpCall ——同步/異步請求
    |
    |
    |
   V
CallAdapter
    經過將網絡請求執行庫OkHttpCall轉換成適合不一樣平臺適用的可調用的網絡請求的模式。
    |
    |
    |
   V
Converter
    對返回的數據使用以前產生的GsonConverter,解析返回的數據獲得Response對象
    |
    |
    |
   V
 CallBackExecutor
     線程切換類,只針對於異步請求  ;將子線程網絡請求結果回調到主線程進行UI顯示
    

ProGuard

4、簡單的實例代碼 Simple Demo
 
   一、建立 接口方法
//接口方法裏添加註解方法
public interfaceGitHubService {
    //Get註解:表示ListRepos()方法是一個Get請求-@POST、@PUT...
    //(「請求的拼接路徑」)+BaseUrl = 完整的URL 大括號{...}的值內容是動態變化的,是由下面的方法傳遞進來的
   @GET("users/{user}/repos")
    //ListRepos方法——ServiceMethod
   Call<List<Repo>> listRepos(@Path("user") String user);
    //@Path():設置默認Url地址參數值
    // 若是 String user爲null的話 就用括號內的參數做爲默認值傳遞
}
    二、開啓真正網絡請求
public void netRequestWithRetrofit(){
    //一、經過Builder模式構建Retrofit對象,傳入baseUrl
      retrofit = new Retrofit.Builder()
            .baseUrl(" https://api.github.com")
            //建立一個ConverterFactory,將返回的HttpResponse轉換成java對象
           .addConverterFactory(GsonConverterFactory.create())
            .build();
    //二、經過Retrofit對象的create方法傳入Class字節碼,建立自定義的接口實例
    GitHubServiceservice = retrofit.create(GitHubService.class);
    //三、調用接口裏的方法 生成Call對象 
    Call repos =service.listRepos("xxx");
    //四、經過Call對象,進行OkHttp實行網絡請求
    repos.enqueue(new Callback() {
        @Override
        public void onResponse(Call call, Response response) {
        }
        @Override
        public void onFailure(Call call, Throwable t) {
        }
    });
}
5、Retrofit請求的過程
    一、倒入可選資源包,添加網絡權限
//Retrofit引用
implementation "com.squareup.retrofit2:retrofit:$Retrofit_version
 
//conver-gson
implementation "com.squareup.retrofit2:converter-gson:$Converter_gson_version"
implementation "com.squareup.retrofit2:converter-scalars:$Converter_scalars_version"
 
//adapter-rxjava
implementation "com.squareup.retrofit2:adapter-rxjava:$Adapter_rxjava_version"
 
//Rx -java /android
implementation "io.reactivex:rxjava:$RxJava_version"
implementation "io.reactivex:rxandroid:$RxAndroid_verison"
//Okhttp
implementation "com.squareup.okhttp3:okhttp:$OkHttp_verison"
 
    二、自定義接收服務端返回數據Bean 類
    三、自定義描述整個網絡請求接口
/**
* 描述整個網絡請求的接口
* */
public interfaceMyInterface {
    @GET(".../...")
    Call<List<Repo>> getCall();
}
        ps:retrofit將每個http請求抽象成java接口
  • 經過註解模式描述和配置網絡請求參數
  • 經過動態代理模式將整個接口的註解翻譯成了一個個http請求再由線程池執行
  • 接口中的每一個方法的參數都必須用註解的方式
 
    四、建立Retrofit實例
//建立Retrofit對象 ,baseUrl+@GET(...) =完整地址
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("") //設置網絡請求的Url地址
        .addConverterFactory(GsonConverterFactory.create()) //設置數據解析器
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //支持RxJava平臺等網絡平臺適配器
        //ps:使用默認的網絡請求適配器不然須要添加依賴
        .build();
 
五、建立 網絡請求接口實例
//建立網絡請求接口實例,傳入接口字節碼文件
MyInterfacemyInterface = retrofit.create(MyInterface.class);
 
六、發送網絡請求
//調用接口裏的方法獲取Call實例
Callcall = myInterface.getCall();
call.enqueue(new Callback() {
七、處理服務器返回的數據
       @Override
        public void onResponse(Call call, Response response) {
        }
        @Override
        public void onFailure(Call call, Throwable t) {
        }
    });
}
 
6、代理模式
 
爲其餘對象提供一種代理,用以控制對這個對象的訪問。
 
    一、靜態代理-抽象類
 

 
AbstractObject :抽象對象角色
 聲明目標類和代理類對象的共同抽象方法;
意義ps:該類定義的方法是ProxyObject和RealObject 共同所要繼承的!
            在任何地方可使用RealObject的時候都適用ProxyObject
/**
* 須要被目標類和代理類共同繼承的抽象方法
*/
public abstractclass AbstractObject {
    protected abstractvoid operation();
}
 
RealObject:目標對象角色
    定義代理對象所表明的目標對象
/**
* 目標類,繼承自AbstractObject
* */
public class RealObject extends AbstractObject {
    @Override
    protected void operation() {
        System.out.println("");
    }
}
 
ProxyObject:代理對象角色
    持有一個目標對象RealObject的引用,能夠在任什麼時候候操做or 替換 目標對象
/**
* 代理類對象,一樣繼承自AbstractObject
*/
public class ProxyObject extends AbstractObject {
    //持有一個目標類對象的引用
    private RealObject realObject;
    public ProxyObject(RealObject realObject) {
        this.realObject = realObject;
    }
    @Override
    protected void operation() {
    //在該方法中能夠添加更多邏輯 ——靜態代理做用之一
        System.out.println("do sth before real operation..");
        if (realObject == null) {
            realObject = new RealObject();
        }
        realObject.operation();
        System.out.println("do sth after real operation...");
    }
}
 
    從這個代碼實例能夠看出:代理對象將客戶端的調用委派給了目標對象,而在調用目標對象以前和以後均可以執行某些特定操做。也就是說調用    realObject.operation();以前和以後均可以加本身的判斷。
 
 
ps:要對已有方法進行改進的話,能夠採用代理模式。採用一個代理類調用原來的方法對產生的結果進行控制這就是所說的靜態代理。
 
靜態代理優勢:
    使得功能更加清晰,便於後期的代碼維護。
 
    二、動態代理
2.1 定義
    代理類在程序運行時建立的代理方式。也就是說代理類並非在Java代碼中定義的而是根據配置在運行時動態生成的。
 
2.2 動態代理優勢:
  •         無侵入      :無侵入式擴展代碼
  •         通俗          :在不修改源代碼的狀況下加強方法或是修改代碼,在方法的執行先後進行其餘操做
  •         相對於靜態代理   :能很方便的對代理類函數進行統一處理而不用頻繁的修改代理類的每個函數根據業務邏輯
 
2.3 動態代理的寫法
 
    2.3.1 jdk 動態代理
        由Java內部反射機制實現,由於生成類的操做比較高效。可是須要客戶端手動配置輔助接口進行操做
    ps:只能爲接口建立代理
/**
* 代理類和被代理類都須要執行的操做
* */
public interfaceSubjects {
    void shopping();
}
/**
* 真是對象 or 被代理類 實現接口
* */
public class Man implements Subjects{
    @Override
    public void shopping() {
    }
}
/**
* 代理類 ;繼承自InvocationHandler,並實現invoke方法(每個代理類必須實現該接口)
* 代理對象調用程序時候所必須實現的接口
*/
public class Proxyimplements InvocationHandler{
    private Objecttarget; //要代理的真實對象
    public Proxy(Subjectstarget) {
        this.target = target;
    }
    /**
     * @param proxy:指代真實對象的代理
     * @param method:調用的真實對象的某個方法的method對象
     * @param args:所代理的真實對象的某個方法的全部參數
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
           method.invoke(target, args);
        return null;
    }
}
 
ps:調用反射類中的Proxy類中的newProxyInstance()方法,而後根據傳進來的Class字節碼對象生成相對應的實例也就是代理類。每當代理類執行方法的時候就會執行InvocationHandler裏面的invoke方法。由於InvocationHandler同時也是newProxyInstance()方法的一個參數。
 
InvocationHandler
每一個代理類的對象都會關聯一個表示內部處理邏輯的InvocationHandler接口的實現
  •     當使用者調用了代理對象所代理的接口中的方法的時候,這個調用信息就會被傳遞到InvocationHandler中的invoke方法中;
  •     invoke方法的參數中能夠獲取所須要的代理對象以及方法對應的method對象和其方法的實際參數;
  •     invoke方法的返回值會被返回給使用者
 
public class Client {
    public static void main(String[] args) {
      //一、實例化接口對象,並經過傳遞接口對象實例化參數生成Proxy代理對象
       Subjects man = new Man();
        Proxy proxy = new Proxy(man);
        //二、經過java.lang.reflect.newProxyInstance(...)方法獲取真實對象的代理對象
//man.getClass().getClassLoader() 就是代理類
        Subjects subjects = (Subjects)java.lang.reflect.Proxy.newProxyInstance(
                man.getClass().getClassLoader(), man.getClass().getInterfaces(), proxy);
        //三、經過代理對象調用真實對象相關接口中實現的方法,這個時候就會跳轉到這個代理對象所關聯的Handler的invoke()方法中
        subjects.shopping();
        //四、獲取真實對象的代理對象所對應的class對象的名稱,用字符串表示
        System.out.println(subjects.getClass().getName());
    }
}
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
ClassLoader:類加載器 動態生成的字節碼文件加載到JVM虛擬機當中
Class<?>interfaces: 爲代理對象提供的接口,被代理實現的接口
InvocationHandler:當代理對象調用方法的時候,關聯到該對象上調用其invoke方法
 
    2.3.2 CGLIB
        直接修改字節碼
 
動態代理小結
  •     運行期
        經過代理類與相關接口不直接聯繫的狀況下而在運行時實現動態管理
    •     InvocationHandler接口 和 Proxy類
    •     動態代理與靜態代理最大的不一樣 ;
    動態代理的代理類不須要手動生成,該代理類是在運行期間動態生成的,該代理類已經實現了相關接口
 
7、Retrofit 源碼
 
7.1 網絡通訊步驟
    a、建立Retrofit實例
    b、定義一個網絡請求接口 併爲接口中的方法添加註解
    c、經過 動態代理生成 網絡請求對象
    d、經過網絡請求適配器 將網絡請求對象進行平臺適配
    e、經過網絡請求適配器Call 發送網絡請求
    f、 經過GsonConverter數據轉換器解析數據
    g、經過回調執行器切換線程
    h、用戶在主線程處理返回結果
 
7.2 Retrofit 源碼解析
 
工廠設計模式:
    將類實例化的操做與使用對象的操做分開,客戶端不須要關心具體參數經過Factory類靜態方法建立須要的對象。
 
Retrofit 七個關鍵成員變量:
 
/**
*一、緩存Map對象
*key值:Method=Http請求方法  
*value值:ServiceMethod=網絡請求接口中對其方法進行註解後,經過解析以後的對象
*serviceMethodCache:使用於網絡請求緩存 、各類配置等信息
*/
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
 
/**二、請求網絡OkHttp工廠*/
final okhttp3.Call.Factory callFactory;
 
/**三、請求網絡基礎地址*/
final HttpUrl baseUrl;
 
/**四、數據轉換器工廠集合,針對response進行的轉換*/
final List<Converter.Factory> converterFactories;
 
/**五、網絡請求適配器工廠集合,將Call對象轉換成其餘類型,生產Calladapter*/
final List<CallAdapter.Factory> callAdapterFactories;
 
/**六、執行回調操做處理異步請求,在Android中默認使用MainExecutor 主線程Executor*/
final @Nullable Executor callbackExecutor;
 
/**七、表示位;是否須要當即解析接口的方法和參數所用*/
final boolean validateEagerly;
 
7.3 Retrofit中的builder構建者模式
Retrofit retrofit = new Retrofit.Builder()
public static final class  Builder{
  private final Platform platform; 
  private @Nullable okhttp3.Call.Factory callFactory;
  private HttpUrl baseUrl;
  private final List<Converter.Factory> converterFactories = new ArrayList<>();
  private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
  private @Nullable Executor callbackExecutor;
  private boolean validateEagerly;
    …
}
經過構建者模式把Retrofit當中的成員變量初始化;
 
Platform://返回一個Platform對象 也就是適配的平臺
public Builder() { //builder無參構造方法
  this(Platform.get());
}
經過findPlatform()方法初始化 PLATFORM實例
private static Platform findPlatform() {
  try {
   //經過Java的反射機制,class的靜態方法ForName,查找指定的類,並返回該對象 如Android
        Class.forName("android.os.Build");
            if (Build.VERSION.SDK_INT != 0) {
              return new Android();
            }
      } catch (ClassNotFoundException ignored) {
  }
 
Android():
static class Android extends Platform {
    //一、返回一個默認的回調方法執行器,用於切換線程,從子線程切換到主線程,在主線程中執行回調方法
  @Override 
    public Executor defaultCallbackExecutor() {
    return new MainThreadExecutor();
  }
   //二、建立默認的網絡請求適配器工廠;使得call請求在異步調用時候會指定Executor執行器來執行回調
  @Override 
    CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor == null) throw new AssertionError();
    return new ExecutorCallAdapterFactory(callbackExecutor);
  }
   //三、這個Executor,傳入Looper.getMainLooper()進行主線程綁定操做,這是能夠在主線程中回調方法的緣由
  static class MainThreadExecutor implements Executor {
    private final Handler handler = new Handler(Looper.getMainLooper());
    @Override public void execute(Runnable r) {
      handler.post(r);
    }
  }
}
//將剛纔獲得的Platform對象賦值給Builder內部類的成員變量platform 來初始化
Builder(Platform platform) {
  this.platform = platform;
}
//在數據轉換器工廠當中添加BuiltInConverters()對象
converterFactories.add(new BuiltInConverters());
BuiltInConverters:若初始化時候沒有指定數據轉換器工廠,Retrofit回提供內置的默認數據轉換器工廠
++++++
.baseUrl(" https://api.github.com」) 
做用: 對String 類型的Url 進行格式轉換 HttpUrl
public Builder baseUrl(String baseUrl) {
  checkNotNull(baseUrl, "baseUrl == null");
  HttpUrl httpUrl = HttpUrl.parse(baseUrl);
  if (httpUrl == null) {
    throw new IllegalArgumentException("Illegal URL: " + baseUrl);
  }
  return baseUrl(httpUrl);
}
baseUrl:
//將HttpUrl類型參數拆分紅多個獨立的部分 並檢查最後一個集合 地址最後是否是「/」 結尾
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
  throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
++++++
   //建立一個ConverterFactory,將返回的HttpResponse轉換成java對象
.addConverterFactory(GsonConverterFactory.create())
//將RxJava適配器添加到適配器工廠中 完成適配器添加操做
addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 
//將(...)轉換器工廠加入到集合當中
public Builder addConverterFactory(Converter.Factory factory) {
  converterFactories.add(checkNotNull(factory, "factory == null"));
  return this;
}
GsonConverterFactory.create():建立一個含有gson對象實例的ConverterFactory
 
//返回一個含有scheduler對象的RxJavaCallAdapterFactory
public static RxJavaCallAdapterFactory create() {
  return new RxJavaCallAdapterFactory((scheduler)null); 
}
private final Scheduler scheduler;//RxJava的調度器
        
++++++
RxJavaCallAdapterFactory的工做
public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
    Factory是定義在接口CallAdapter裏的抽象方法
理論流程:
    一、獲取Call<T>對象,執行具體Http請求
    二、獲取到服務端返回的數據 ,調用converter()把數據轉換成java
 
實現 RJCAF的流程:
    a、實現CallAdapter的抽象類Factory,提供具體的適配邏輯
    b、將CallAdapter()經過Add方法註冊到Retrofit中
    c、經過Factory.get()方法獲取CallAdapter
    d、調用Adapter中的adapt(),將Call請求轉換成適合的平臺所適用的類型
 
RxJavaCallAdapterFactory源碼
@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
   //獲取到數據原始類型
  Class<?> rawType = getRawType(returnType);
            …   
   //最終回返回一個CallAdapter對象
    CallAdapter<Observable<?>> callAdapter = getCallAdapter
                                        (returnType,scheduler);
            if (isSingle) {
                  return SingleHelper.makeSingle(callAdapter);
            }
        return callAdapter;
++++++
CallAdapter的做用:
    將Retrofit中的Call<T>對象轉換成Java中的對象,來進行其餘操做
區別於OkHttp中的Call:
    進行了二次封裝,實際都是調用的OkHttp的請求
 
Call<T> —> converter —>  java 對象
public interface CallAdapter<R, T> {
    Type responseType(); //返回Http解析後的類型(接口返回類型中範型參數的實參:List<repos> 表明list集合對象)而不是接口的返回類型
    T adapt(Call<R> call); // T:須要轉換成接口的返回類型,這裏的call就是OkHttpCall的實例 
abstract class Factory {
   //根據接口的註解類型來獲得實際須要的CallAdapter
    public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,Retrofit retrofit);
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
  return Utils.getParameterUpperBound(index, type);
}
   //獲取原始類型
    protected static Class<?> getRawType(Type type) {
  return Utils.getRawType(type);
}
CallAdapter有三個具體的實現類 :RRS 
ResponseCallAdapter
ResultCallAdapter
SimpleCallAdapter
以ResponseCallAdapter()爲例:
@Override 
public <R> Observable<Response<R>> adapt(Call<R> call) {
    //建立一個Observable被觀察者實例,會將獲取到的Call對象做爲參數傳遞,進行call對象與被觀察者的關聯操做,若是不爲空就調用observable.subscribeOn()方法,完成適配工做。
    Observable<Response<R>> observable = Observable.create(new CallOnSubscribe<>(call));
    if (scheduler != null) {
        //開始執行Retrofit的網絡請求
      return  observable.subscribeOn(scheduler);
    }
    return observable;
  }
}
++++++
.build():
//經過build類配置Retrofit中的全部成員變量
public Retrofit build() {
    //若baseUrl爲空則拋出異常
  if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.」);//網絡請求是必須的不能缺失
  }
    //實際的Http請求,call若是爲空則默認建立一個OkHttp請求 
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
  callFactory = new OkHttpClient();
}
    //初始化異步請求回調執行器
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
  callbackExecutor = platform.defaultCallbackExecutor();//建立主線程executor
}
//將網絡請求適配器工廠做爲參數傳入到list當中
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//將平臺默認的工廠添加到集合當中
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
 
//建立配置數據轉換器工廠
List<Converter.Factory> converterFactories =
    new ArrayList<>(1 + this.converterFactories.size());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
//將以上變量均做爲參數傳遞給Retrofit
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
        unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
  }
}
 
7.4 Retrofit中的 網絡請求接口實例
 
@GET(「…」):若註解方法中是完整的url地址 ,在build中的baseurl能夠不設置。
經過外觀模式和動態代理模式適用create方法
GitHubService service = retrofit.create(GitHubService.class);
retrofit.create():
//判斷是否提早驗證、解析接口,返回true則提早驗證
if (validateEagerly) {
  eagerlyValidateMethods(service);
}
ps:內方法解析
eagerlyValidateMethods():
private void eagerlyValidateMethods(Class<?> service) {
    //獲取一個當前的平臺信息,Android/ Java /Ios
    Platform platform = Platform.get();
   //經過反射機制獲取接口裏的方法,並對接口裏的方法進行遍歷
  for (Method method : service.getDeclaredMethods()) {
    //isDefaultMethod默認返回false因此會調用loadServiceMethod
    if (!platform.isDefaultMethod(method)) {
      loadServiceMethod(method);
    }
  }
}
loadServiceMethod(): 核心方法
一個ServiceMethod對應一個接口的http請求方法,裏面含有衆多網絡請求配置參數
 
ServiceMethod<?, ?> loadServiceMethod(Method method) {
  ServiceMethod<?, ?> result = serviceMethodCache.get(method);
  if (result != null) return result;
//經過synchronized線程鎖確保 緩存ServiceMethod對象的線程緩存安全
  synchronized(serviceMethodCache) {
    //每次讀取的時候會先從serviceMethodCache中獲取,若能找到相應的serviceMethodCache對象就不建立新的
    result = serviceMethodCache.get(method);
    if (result == null) {
      result = new ServiceMethod.Builder<>(this, method).build();
   // 將serviceMethod做爲key傳入到 serviceMethodCache中進行緩存
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}
 
繼續下面的邏輯:
//返回一個網絡請求接口的動態代理對象:經過動態代理建立網絡請求的接口實例
return (T) Proxy.newProxyInstance(service.getClassLoader(),
                                  new Class<?>[] { service },
                                  new InvocationHandler() {
 //傳入一個Class對象生成一個實例即爲代理對象,每當執行代理類的方法的時候就會調用InvocationHandler()方法的invoke()方法,解析方法註解等等
        private final Platform platform = Platform.get();
    //invoke真正進行解析接口操做的方法
        @Override public Object invoke(Object proxy, Method method, 
                                            @Nullable Object[] args)
            throws Throwable {
          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.adapt(okHttpCall);
        }
      });
}
 
7.5 Retrofit中的ServiceMethod對象
loadServiceMethod():
ServiceMethod<?, ?> loadServiceMethod(Method method) {
  ServiceMethod<?, ?> result = serviceMethodCache.get(method);
  if (result != null) return result;
  synchronized (serviceMethodCache) {
    //一、單例模式建立ServiceMethodCache對象
    result = serviceMethodCache.get(method);
        if (result == null) {
    //二、沒有緩存 建立一個ServiceMethodCache對象,經過構建者模式build內部類建立
          result = new ServiceMethod.Builder<>(this, method).build();
    //三、將建立好的ServiceMethodCahce對象放入到Cache緩存池當中  ,以http請求方法做爲key,以serviceMethod對象做爲value保存到緩存池當中
      serviceMethodCache.put(method, result);
        }
  }
  return result;
}
 
ServiceMethod對象包含了全部網絡請求的基本信息,全部能夠發現ServiceMethod的初始化和Retrofit初始化很類似,均是經過構建者模式build類進行構建的
ServiceMethod.Builder():
Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
//獲取網絡請求裏方法的註解
  this.methodAnnotations = method.getAnnotations(); 
//獲取網絡請求方法裏參數的類型
  this.parameterTypes = method.getGenericParameterTypes();
//方法裏註解完整的內容
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}
 
//根據網絡請求返回值的類型和方法中的註解,來從網絡請求適配器工廠和數據轉換器工廠集合中分別獲取到所須要的網絡請求適配器和數據轉換器。根據參數的註解獲取到所須要的參數,最後調用parseParameter()解析接口中的參數
 
public ServiceMethod build() {
    //建立網絡請求適配器,獲取網絡請求接口裏方法的返回類型,調用Retrofit的callAdatper()方法,根據返回類型值(選擇具體須要哪一種工廠)和註解類型判斷須要什麼適配器
在nextCallAdapter()中 ,遍歷callAdapter工廠集合,經過get方法建立須要的CallAdapter
    callAdapter = createCallAdapter();
//同理下面的建立數據轉換器工廠
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?");
}
        ...
responseConverter = createResponseConverter();
}
//遍歷網絡請求中方法的註解
for (Annotation annotation : methodAnnotations) {
  parseMethodAnnotation(annotation);
    //對接口中的方法進行解析
}
    …
//獲取當前方法的長度:
int parameterCount = parameterAnnotationsArray.length;
    …
//解析請求方法裏的參數
parameterHandlers[p] = parseParameter(p, 
                        parameterType, parameterAnnotations);
 
ParameterHandler:方法參數的解析處理器
 
//構造函數完成OkHttpCall的建立
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);    
 OkHttpCall 實現接口Call
final class OkHttpCall<T> implements Call<T> {
 
//OkHttp庫的原生的Call對象,表明實際的網絡請求call
private @Nullable okhttp3.Call rawCall;
//網絡請求參數信息的對象 請求信息各種
private final ServiceMethod<T, ?> serviceMethod;
//網絡請求接口的參數
private final @Nullable Object[] args;
//狀態標誌位,再請求網絡的時候判斷是否取消這個call,也就是說是否cancel掉該請求
private volatile boolean canceled;
//請求異步方法的時候來判斷執行邏輯
private boolean executed;
 
構造函數完成OkHttpCall的建立 //serviceMethod,輸入的請求參數args
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
  this.serviceMethod = serviceMethod;
  this.args = args;
}
 
//經過適配器的adapt方法,將建立好的OKhttpCall對象傳遞到adapt方法來獲取返回值
return serviceMethod.adapt(okHttpCall);
//在serviceMethod的build內部類裏,經過構建者模式的內部類進行的callAdatper的賦值
 
.adapt 適用Java中的適配器模式進行類型轉換,將retrofit的call轉換成其餘平臺也能使用的call
 
//調用接口裏的方法獲取Call實例,使用動態代理,返回給一個OkHttpCall類型的對象進行網絡請求
接口中調用getCall()實際上就是經過OkHttp庫請求網絡而後再執行同步/異步方法
Call call = myInterface.getCall();
 
ps:這裏有了Call不能直接發送請求,由於缺乏請求頭、實體信息等內容
 
7.5 Retrofit 同步/異步請求
 
Retrofit 封裝接口,OkHttp庫負責底層網絡實現
    精妙:Retrofit經過註解和接口將Http請求進行更好封裝,然後又經過動態代理來解析定義好的註解和方法的參數
 
同步:OkHttpCall.execute()
異步:OkHttpCall.enqueue() 
區別: 異步請求會將回調方法交給回調執行器execute完成,由回調執行器execute來指定不一樣的線程完成不一樣的操做
 
同步:
步驟
   一、解析網絡請求接口中每個方法和參數 利用ParameterHandler解析
    二、利用ServiceMethod對象(包含全部)建立一個OkHttp庫的Request對象,進行實際網絡請求
            ps:ServiceMethod對象會被緩存到ServiceMethodCache中來提升使用效率
    三、經過OkHttp的底層 call,OkHttp發送網絡請求
    四、converter GsonConverterFactory默認解析數據
 
@Override public Response<T> execute() throws IOException {
     //建立一個OKHttp庫的Call對象進行操做,說明Retrofit最終都是經過OkHttp庫實現的
    okhttp3.Call call;
 
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already executed.");
        …
    }
  call = rawCall;
    if (call == null) {
      try {
    //經過該方法建立一個Request對象請求,返回值返回給call
        call = rawCall = createRawCall();
        
    //解析完成後,返回Response ,經過阻塞方法返回數據
  return parseResponse(call.execute());
}
createRawCall():
//經過toCall生成 call對象
private okhttp3.Call createRawCall() throws IOException {
  okhttp3.Call call = serviceMethod.toCall(args);
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}
serviceMethod.toCall(): 
經過ParameterHandler 函數對網絡請求接口中的方法和參數進行解析 
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
  RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
      contentType, hasBody, isFormEncoded, isMultipart);
 
  @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
  ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
 
  int argumentCount = args != null ? args.length : 0;
  if (argumentCount != handlers.length) {
    throw new IllegalArgumentException("Argument count (" + argumentCount
        + ") doesn't match expected count (" + handlers.length + ")");
  }
        …
   //交給OkHttpCall庫的實現類
    return callFactory.newCall(requestBuilder.build());
}
callFactory.newCall():
@Override public Call newCall(Request request) {
    //OkHttp庫的Call的實現類RealCall
  return RealCall.newRealCall(this, request, false /* for web socket */);
}
 
parseResponse():
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
     //獲取響應體
    ResponseBody rawBody = rawResponse.body();
    //經過響應體的構建者模式獲取響應信息
  rawResponse = rawResponse.newBuilder()
      .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
      .build();
    //獲取響應碼而後進行響應的判斷
  int code = rawResponse.code();
    …
T body = serviceMethod.toResponse(catchingBody);
       //實際上toResponse()調用的就是數據轉換器,將response轉換成須要的Java對象
    R toResponse(ResponseBody body) throws IOException {
          return responseConverter.convert(body);
    }
return Response.success(body, rawResponse);
        ….
}
   
異步:  call.enqueue(new Callback() {...}
 
@Override public void enqueue(final Callback<T> callback) {
  checkNotNull(callback, "callback == null");
//與同步操做相似首先也是建立OkHttp庫的Calld對象
  okhttp3.Call call;
  Throwable failure;
        …
    try {
       //與同步邏輯處理操做一直以後
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
        ….
 
        //實現真正的異步請求
call.enqueue(new okhttp3.Callback() {
  @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
    Response<T> response;
    try {
    //okHttp解析返回的Response,經過converter轉換成須要的Java數據
      response = parseResponse(rawResponse);
    } catch (Throwable e) {
      callFailure(e);
      return;
    }
    …
   try {
        //在本身的代碼回調方法中進行邏輯處理
      callback.onResponse(OkHttpCall.this, response);
    } catch (Throwable t) {
          t.printStackTrace();
    }
相關文章
相關標籤/搜索