美文网首页Android开发经验谈Android开发Android文章
Android小知识-剖析Retrofit中静态内部类Build

Android小知识-剖析Retrofit中静态内部类Build

作者: 爱读书的顾先生 | 来源:发表于2018-11-02 10:49 被阅读155次

    本平台的文章更新会有延迟,大家可以关注微信公众号-顾林海,包括年底前会更新kotlin由浅入深系列教程,目前计划在微信公众号进行首发,如果大家想获取最新教程,请关注微信公众号,谢谢!

    在上章节《Android小知识-剖析Retrofit中的网络请求流程以及相关参数》中介绍了Retrofit的成员变量,以及静态内部类Builder中的成员变量,本节继续讲解Builder类中的相关方法。

    Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://icould.glh/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
    

    通过Builder的baseUrl方法来设置http的基地址,先进入baseUrl方法。

        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方法中,将传入的String类型的baseUrl通过HttpUrl的parse方法转换成HttpUrl对象,将转换后的httpUrl实例传入baseUrl方法,注意这里传入baseUrl方法的是HttpUrl对象,我们继续看baseUrl(HttpUrl)方法。

        public Builder baseUrl(HttpUrl baseUrl) {
          checkNotNull(baseUrl, "baseUrl == null");
          List<String> pathSegments = baseUrl.pathSegments();
          if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
            throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
          }
          this.baseUrl = baseUrl;
          return this;
        }
    

    通过checkNotNull方法判断HttpUrl对象是否为空,接着通过HttpUrl的pathSegments()方法将url拆分成多个独立的碎片,为了方便比较,将创建Retrofit实例贴出来:

    Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://icould.glh/")
    

    通过baseUrl方法设置http的url时,在最后是以'/'反斜杠结尾的,下面的if语句中判断拆分后的最后字符串是否为空,拆分后的数组最后一个为空,说明http的url是以'/'结尾,反之http的url不是以'/'结尾,就会抛出异常,最后将baseUrl赋值给Builder的成员变量baseUrl。

    介绍完baseUrl方法,继续看下一个方法addConverterFactory方法:

            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://icould.glh/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
    

    addConverterFactory方法是用于设置数据解析器,进入addConverterFactory方法看看到底做了哪些操作。

        public Builder addConverterFactory(Converter.Factory factory) {
          converterFactories.add(checkNotNull(factory, "factory == null"));
          return this;
        }
    

    addConverterFactory方法所做的工作很简单,就是将factory添加到数据解析器工厂的集合中。回到前面addConverterFactory方法,看到传入的是GsonConverterFactory对象,而GsonConverterFactory对象是通过GsonConverterFactory的get()方法创建的,点进去看下。

      public static GsonConverterFactory create() {
        return create(new Gson());
      }
    

    create方法内部先是创建了Gson对象,这个Gson就是goole提供的Gson,用于解析json数据用的,创建完Gson对象后调用create方法并传入刚创建后的Gson对象。

      public static GsonConverterFactory create(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        return new GsonConverterFactory(gson);
      }
    

    方法很简单,创建一个GsonConverterFactory对象并返回,我们进入GsonConverterFactory的构造函数中。

      private final Gson gson;
    
      private GsonConverterFactory(Gson gson) {
        this.gson = gson;
      }
    

    GsonConverterFactory的构造函数只做了赋值操作,将创建好的Gson对象赋值给GsonConverterFactory的成员变量gson。

    介绍完addConverterFactory方法后,接着看addCallAdapterFactory方法:

            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://icould.glh/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
    

    addCallAdapterFactory方法用于设置适配的平台,这里使用的是RxJava平台,我们看下addCallAdapterFactory的具体操作。

        public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
          callAdapterFactories.add(checkNotNull(factory, "factory == null"));
          return this;
        }
    

    代码还是很简单,就是将factory添加到适配器工厂的集合中去。回到前面,看看addCallAdapterFactory方法传入的这个Factory,是通过RxJavaCallAdapterFactory工厂类的create()方法来创建的。

      public static RxJavaCallAdapterFactory create() {
        return new RxJavaCallAdapterFactory(null, false);
      }
    

    create方法内部直接通过new关键字创建了RxJavaCallAdapterFactory对象。

    public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
      ...
    }
    

    RxJavaCallAdapterFactory继承了CallAdapter的内部类Factory。

    先看CallAdapter的作用,CallAdapter作用就是通过Retrofit中Call<T>转换成Java对象,Retrofit中的Call对象和OkHttp中的Call对象是不一样的,Retrofit中的Call是对OkHttp中的Call进行了封装,也就是说通过Retrofit来进行网络请求,最终都是通过OkHttp来进行请求的。在转换Java对象前,需要先创建Retrofit中的Call对象,然后通过Call对象发送http请求,服务器会返回响应的数据,这个时候通过converter数据转换器,将服务器返回的Response转换成我们需要的Java对象。

    public interface CallAdapter<R, T> {
    
        Type responseType();
    
        T adapt(Call<R> call);
    
    
    }
    

    在CallAdapter接口中定义了一个responseType()方法并返回Type类型,这个方法的作用就是返回解析后的类型。看下面网络请求接口:

    public interface NetworkInterface {
        @GET("news/newsDetail")
        Call<MyResponse> getNewsDetails(@QueryMap Map<String,String> map);
    }
    

    CallAdapter接口中的responseType方法返回的就是MyResponse这个类型的对象。

    public interface CallAdapter<R, T> {
    
        Type responseType();
    
        T adapt(Call<R> call);
    
    
    }
    

    继续看第二个方法adapt,这里的泛型T是指需要转换接口的返回类型,adapt方法传入一个Call对象,这个Call对象就是OkHttp的Call对象,如果对应的是RxJava的话,这里的T对应的就是RxJava当中的类型。

    继续看CallAdapter内部类Factory:

    public interface CallAdapter<R, T> {
    
        ...
    
        abstract class Factory {
            public abstract @Nullable retrofit2.CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
                                            Retrofit retrofit);
    
            ...
    
            protected static Class<?> getRawType(Type type) {
                return Utils.getRawType(type);
            }
        }
    }
    

    get方法的作用是根据接口的返回类型以及注解类型来得到实际需要的CallAdapter;getRawType方法返回的是原始的类型。

    RxJavaCallAdapterFactory实现Factory抽象类,用来提供具体的适配逻辑,回到RxJavaCallAdapterFactory,先看get方法的实现:

        @Override
        public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
            Class<?> rawType = getRawType(returnType);
            ...
            return new RxJavaCallAdapter(responseType, scheduler, isAsync, isResult, isBody, isSingle,
                    false);
        }
    

    在get方法中,先通过getRawType拿到原始数据类型,通过这个原始数据类型进行各种设置,最后创建RxJavaCallAdapter对象并返回。创建完RxJavaCallAdapter对象后,最终调用adapt方法将我们的Call请求转换成每一个平台所适用的类型。adapt方法在接口CallAdapter中定义的,在源码中找到RxJavaCallAdapter实现了CallAdapter接口,我们看看RxJavaCallAdapter中的adapt实现。

        @Override public Object adapt(Call<R> call) {
            Observable.OnSubscribe<Response<R>> callFunc = isAsync
                    ? new CallEnqueueOnSubscribe<>(call)
                    : new CallExecuteOnSubscribe<>(call);
    
            Observable.OnSubscribe<?> func;
            if (isResult) {
                func = new ResultOnSubscribe<>(callFunc);
            } else if (isBody) {
                func = new BodyOnSubscribe<>(callFunc);
            } else {
                func = callFunc;
            }
            Observable<?> observable = Observable.create(func);
    
            if (scheduler != null) {
                observable = observable.subscribeOn(scheduler);
            }
            if (isSingle) {
              return observable.toSingle();
           }
           if (isCompletable) {
              return observable.toCompletable();
            }
            return observable;
        }
    

    使用过RxJava的同学应该对上面的代码非常熟悉了,将我们传入的OkHttp的Call对象设置给OnSubscribe对象,接着创建Observable被观察者的实例,并将OnSubscribe与被观察者绑定,最后判断scheduler调度器是否为空,如果不为空,就调用observable的subscribeOn方法在指定的调度器执行操作。关于RxJava的相关知识后面会另开文章进行讲解,这里大家先有个印象,知道整体的流程即可。

    到这里baseUrl、addConverterFactory以及addCallAdapterFactory方法就介绍完毕。


    838794-506ddad529df4cd4.webp.jpg

    搜索微信“顾林海”公众号,定期推送优质文章。

    相关文章

      网友评论

        本文标题:Android小知识-剖析Retrofit中静态内部类Build

        本文链接:https://www.haomeiwen.com/subject/yyuqxqtx.html