阅读 201

Android小知识-剖析Retrofit中静态内部类Builder的三个方法

本平台的文章更新会有延迟,大家可以关注微信公众号-顾林海,包括年底前会更新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转换成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

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

关注下面的标签,发现更多相似文章
评论