zoukankan      html  css  js  c++  java
  • Android 常用开源框架源码解析 系列 (三)网络框架之一 Retrofit

    Retrofit
     
    一、定义
     对OkHttp网络请求框架的封装 !不是一个网络请求框架
     
    二、概述
    A type-safe HTTP client for Android and Java
    将每一个Http api请求转换成Java接口,专注于接口层的封装工作
     
    Retrofit是一个RestFul Http ,对底层网络请求框架的封装,完成各类数据的转换和适配工作
     
    • App通过Retrofit 请求网络,实际上说使用Retrofit接口层封装请求参数,之后由OkHttp完成后续实际请求操作
    • 在服务端返回数据之后,OkHttp将原始的结果交给Retrofit,Retrofit根据用户的需求对结构进行解析
     
    三、流程
     
    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

    四、简单的实例代码 Simple Demo
     
       1、创建 接口方法
    //接口方法里添加注解方法
    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的话 就用括号内的参数作为默认值传递
    }
        2、开启真正网络请求
    public void netRequestWithRetrofit(){
        //1、通过Builder模式构建Retrofit对象,传入baseUrl
          retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com")
                //创建一个ConverterFactory,将返回的HttpResponse转换成java对象
               .addConverterFactory(GsonConverterFactory.create())
                .build();
        //2、通过Retrofit对象的create方法传入Class字节码,创建自定义的接口实例
        GitHubServiceservice = retrofit.create(GitHubService.class);
        //3、调用接口里的方法 生成Call对象 
        Call repos =service.listRepos("xxx");
        //4、通过Call对象,进行OkHttp实行网络请求
        repos.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
            }
            @Override
            public void onFailure(Call call, Throwable t) {
            }
        });
    }
    五、Retrofit请求的过程
        1、倒入可选资源包,添加网络权限
    //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"
     
        2、自定义接收服务端返回数据Bean 类
        3、自定义描述整个网络请求接口
    /**
    * 描述整个网络请求的接口
    * */
    public interfaceMyInterface {
        @GET(".../...")
        Call<List<Repo>> getCall();
    }
            ps:retrofit将每一个http请求抽象成java接口
    • 通过注解模式描述和配置网络请求参数
    • 通过动态代理模式将整个接口的注解翻译成了一个个http请求再由线程池执行
    • 接口中的每个方法的参数都必须用注解的方式
     
        4、创建Retrofit实例
    //创建Retrofit对象 ,baseUrl+@GET(...) =完整地址
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("") //设置网络请求的Url地址
            .addConverterFactory(GsonConverterFactory.create()) //设置数据解析器
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //支持RxJava平台等网络平台适配器
            //ps:使用默认的网络请求适配器否则需要添加依赖
            .build();
     
    5、创建 网络请求接口实例
    //创建网络请求接口实例,传入接口字节码文件
    MyInterfacemyInterface = retrofit.create(MyInterface.class);
     
    6、发送网络请求
    //调用接口里的方法获取Call实例
    Callcall = myInterface.getCall();
    call.enqueue(new Callback() {
    7、处理服务器返回的数据
           @Override
            public void onResponse(Call call, Response response) {
            }
            @Override
            public void onFailure(Call call, Throwable t) {
            }
        });
    }
     
    六、代理模式
     
    为其他对象提供一种代理,用以控制对这个对象的访问。
     
        1、静态代理-抽象类
     

     
    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、动态代理
    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) {
          //1、实例化接口对象,并通过传递接口对象实例化参数生成Proxy代理对象
           Subjects man = new Man();
            Proxy proxy = new Proxy(man);
            //2、通过java.lang.reflect.newProxyInstance(...)方法获取真实对象的代理对象
    //man.getClass().getClassLoader() 就是代理类
            Subjects subjects = (Subjects)java.lang.reflect.Proxy.newProxyInstance(
                    man.getClass().getClassLoader(), man.getClass().getInterfaces(), proxy);
            //3、通过代理对象调用真实对象相关接口中实现的方法,这个时候就会跳转到这个代理对象所关联的Handler的invoke()方法中
            subjects.shopping();
            //4、获取真实对象的代理对象所对应的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类
      •     动态代理与静态代理最大的不同 ;
        动态代理的代理类不需要手动生成,该代理类是在运行期间动态生成的,该代理类已经实现了相关接口
     
    七、Retrofit 源码
     
    7.1 网络通信步骤
        a、创建Retrofit实例
        b、定义一个网络请求接口 并为接口中的方法添加注解
        c、通过 动态代理生成 网络请求对象
        d、通过网络请求适配器 将网络请求对象进行平台适配
        e、通过网络请求适配器Call 发送网络请求
        f、 通过GsonConverter数据转换器解析数据
        g、通过回调执行器切换线程
        h、用户在主线程处理返回结果
     
    7.2 Retrofit 源码解析
     
    工厂设计模式:
        将类实例化的操作与使用对象的操作分开,客户端不需要关心具体参数通过Factory类静态方法创建需要的对象。
     
    Retrofit 七个关键成员变量:
     
    /**
    *1、缓存Map对象
    *key值:Method=Http请求方法  
    *value值:ServiceMethod=网络请求接口中对其方法进行注解后,通过解析之后的对象
    *serviceMethodCache:使用于网络请求缓存 、各种配置等信息
    */
    private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
     
    /**2、请求网络OkHttp工厂*/
    final okhttp3.Call.Factory callFactory;
     
    /**3、请求网络基础地址*/
    final HttpUrl baseUrl;
     
    /**4、数据转换器工厂集合,针对response进行的转换*/
    final List<Converter.Factory> converterFactories;
     
    /**5、网络请求适配器工厂集合,将Call对象转换成其他类型,生产Calladapter*/
    final List<CallAdapter.Factory> callAdapterFactories;
     
    /**6、执行回调操作处理异步请求,在Android中默认使用MainExecutor 主线程Executor*/
    final @Nullable Executor callbackExecutor;
     
    /**7、表示位;是否需要立即解析接口的方法和参数所用*/
    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 {
        //1、返回一个默认的回调方法执行器,用于切换线程,从子线程切换到主线程,在主线程中执行回调方法
      @Override 
        public Executor defaultCallbackExecutor() {
        return new MainThreadExecutor();
      }
       //2、创建默认的网络请求适配器工厂;使得call请求在异步调用时候会指定Executor执行器来执行回调
      @Override 
        CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
        if (callbackExecutor == null) throw new AssertionError();
        return new ExecutorCallAdapterFactory(callbackExecutor);
      }
       //3、这个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里的抽象方法
    理论流程:
        1、获取Call<T>对象,执行具体Http请求
        2、获取到服务端返回的数据 ,调用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) {
        //1、单例模式创建ServiceMethodCache对象
        result = serviceMethodCache.get(method);
            if (result == null) {
        //2、没有缓存 创建一个ServiceMethodCache对象,通过构建者模式build内部类创建
              result = new ServiceMethod.Builder<>(this, method).build();
        //3、将创建好的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来指定不同的线程完成不同的操作
     
    同步:
    步骤
       1、解析网络请求接口中每一个方法和参数 利用ParameterHandler解析
        2、利用ServiceMethod对象(包含所有)创建一个OkHttp库的Request对象,进行实际网络请求
                ps:ServiceMethod对象会被缓存到ServiceMethodCache中来提高使用效率
        3、通过OkHttp的底层 call,OkHttp发送网络请求
        4、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();
        }
  • 相关阅读:
    软件架构方面基础-ESB SOA GEO-ESB
    超图软件上市 ——股票代码300036
    python第三方库——xlrd和xlwt操作Excel文件学习
    python -wordcloudan云词安装
    华为手机多屏互动功能使用
    IDL创建泰森多边形
    ArcGIS Engine开发基础总结(一)
    自己制作博客园打赏功能
    Linux学习之八--关闭firewall防火墙安装iptables并配置
    Linux学习之七--mysql的安装使用
  • 原文地址:https://www.cnblogs.com/cold-ice/p/9303473.html
Copyright © 2011-2022 走看看