盘点android中常用的开发库(7) -- Retrofit

一、简介

Retrofit是最流行的Android网络请求库之一,由著名的Square公司开发,适用于Android、Java、Kotlin的类型安全的Http网络请求。Retrofit是基于OkHttp的封装的,它将接口的定义与使用分离开来了,并和RxJava集成的很好,所以对于异步请求、同步请求也不需要做额外的工作。

二、使用

2.1 添加依赖

在app的build.gradle中添加如下代码。

//Retrofit2
implementation 'com.squareup.retrofit2:retrofit:2.9.0'

//Retrofit2 支持的数据转换器 可根据自身数据选择添加依赖
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'        //gson
implementation 'com.squareup.retrofit2:converter-jackson:2.9.0'     //jackson
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'       //moshi
implementation 'com.squareup.retrofit2:converter-protobuf:2.9.0'    //protobuf
implementation 'com.squareup.retrofit2:converter-wire:2.9.0'        //wire
implementation 'com.squareup.retrofit2:converter-simplexml:2.9.0'   //simplexml

当然你也可以选择去Retrofit官网下载最新的Jar包导入的项目中或者使用Maven添加。

<dependency>
  <groupId>com.squareup.retrofit2</groupId>
  <artifactId>retrofit</artifactId>
  <version>2.9.0</version>
</dependency>

2.2 基本使用

第一步 新建一个ApiService文件

retrofit使用Java接口来封装您的Http API,因此我们需要创建一个接口文件,我这里直接命名为ApiService。

/**
 * 封装Http API
 */
public interface ApiService {
    
}

第二步 创建返回对象,并在ApiService中添加接口API 

public interface ApiService {
    
    @GET("/weather/")
    Call<WeatherResult> getWeathers(@Query("city") String city);

}

第三步 创建Retrofit实例,并获取ApiService

通过Builder模式创建Retrofit实例,并通过其create方法获取我们上面新建的ApiService实例。

Retrofit retrofit = new Retrofit.Builder()
        //设置BaseUrl
        .baseUrl(BASE_URL)
        //设置数据解析器
        .addConverterFactory(GsonConverterFactory.create())
        .build();

ApiService apiService = retrofit.create(ApiService.class);

第四步 调用ApiService中的接口获取Call,并调用其execute()\enqueue()实现同步请求\异步请求。

        Call<WeatherResult> call = apiService.getWeathers("杭州");
        //同步请求
        try {
            Response<WeatherResult> response =  call.execute();
            //处理返回结果
        } catch (IOException e) {
            e.printStackTrace();
        }
        //异步请求
        call.enqueue(new Callback<WeatherResult>() {
            @Override
            public void onResponse(Call<WeatherResult> call, Response<WeatherResult> response) {
                //处理返回结果
            }

            @Override
            public void onFailure(Call<WeatherResult> call, Throwable t) {

            }
        });

三、原理分析

熟悉了Retrofit的基本使用还不够,正所谓“知其然,知其所以然”,因此理解它的内部原理也是相当重要的,况且这也是一些面试官喜欢提问的问题。接下来...Let`s start!!!

根据使用步骤首先我们来看看Retrofit这个类。在使用的时候我们是通过Builder模式来创建Retrofit实例的,因此他内部一定存在一个Builder静态内部类,我们着重看下Builder里的各个属性分别表示什么。

public final class Retrofit {
    ...

    public static final class Builder{
        // 表示当前使用的平台 当获取到的vm虚拟机名称为Dalvik则为Android平台
        private final Platform platform;

        // OkHttp3的Call工厂接口,其内部需要实现OkHttp的newCall方法
        private @Nullable okhttp3.Call.Factory callFactory;
        
        // 没什么好讲的 HttpUrl是用来封装Url的,使用此类可以组成或分解网络地址 
        private @Nullable HttpUrl baseUrl;

        // 转换器集合 通过转换器来转换返回结果数据
        private final List<Converter.Factory> converterFactories = new ArrayList<>();

        // CallAdapter集合
        private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
        
        // callback 回调执行器
        private @Nullable Executor callbackExecutor;

        // 验证有效性的boolean
        private boolean validateEagerly;

        ...

        public Retrofit build() {
          if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
          }

          okhttp3.Call.Factory callFactory = this.callFactory;
          if (callFactory == null) {
            callFactory = new OkHttpClient();
          }

          Executor callbackExecutor = this.callbackExecutor;
          if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
          }

          List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
              callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

          List<Converter.Factory> converterFactories =
          new ArrayList<>(
              1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

          converterFactories.add(new BuiltInConverters());
          converterFactories.addAll(this.converterFactories);
          converterFactories.addAll(platform.defaultConverterFactories());

          return new Retrofit(
              callFactory,
              baseUrl,
              unmodifiableList(converterFactories),
              unmodifiableList(callAdapterFactories),
              callbackExecutor,
              validateEagerly);
        }
    }
}

通过Builder我们最终创建了Retrofit实例,并将这些参数按需传入了到Retrofit对应的属性中。这里需要注意的是在构建Retrofit实例时,baseUrl是不能为空的,否则会抛出异常。callFactory为空时,默认创建OkHttpClient。callbackExecutor为空时,默认使用platform的defaultCallbackExecutor()获取,在android平台下返回的是MainThreadExecutor(),那么它是个什么东西呢,实际上就是Handler。

static final class Android extends Platform {
    Android() {
      super(Build.VERSION.SDK_INT >= 24);
    }

    @Override
    public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    ...

    static final class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override
      public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

接下来就是通过Retrofit的create()方法来获取我们所封装的API service接口实例。首先其调用validateServiceInterface方法验证传入的ApiService的有效性,并通过前面我们所提到的validateEagerly的布尔值来判断是否将ApiService中定义的有效方法存入ServiceMethodCache集合中缓存起来。回到create方法,我们可以看到它其实是通过动态代理来创建ApiService动态代理实例。

当我们调用ApiService中的方法时,比如:Call<WeatherResult> call = apiService.getWeathers("杭州"); InvocationHandler就会拦截并执行其invoke方法,这时其三个参数分别表示为:

proxy 对应 ApiService.class; 

method 对应 getWeathers;

args 对应 "杭州";

  @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T)
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {
              private final Platform platform = Platform.get();
              private final Object[] emptyArgs = new Object[0];

              @Override
              public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                // If the method is a method from Object then defer to normal invocation.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

=========================================================================================================================

  private void validateServiceInterface(Class<?> service) {
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }

    ...

    if (validateEagerly) {
      Platform platform = Platform.get();
      for (Method method : service.getDeclaredMethods()) {
        if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
          loadServiceMethod(method);
        }
      }
    }
  }

在platform为Android情况下,其isDefaultMethod方法返回false,因此最终调用loadServiceMethod(method).invoke(args);这里的loadServiceMethod方法是不是有点儿眼熟,没错前面调用validateServiceInterface方法验证传入的ApiService的有效性时最终调用的就是这个方法。它将参数Method解析成ServiceMethod,并存入serviceMethodCache缓存中。

  ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

接下来就是Retrofit的处理请求的核心代码了,首先我们来看下ServiceMethod类,它是一个抽象类,其内部有两个方法parseAnnotations和invoke。parseAnnotations最终调用了HttpServiceMethod的parseAnnotations方法;而invoke方法是个抽象方法,它在HttpServiceMethod中被实现。

  //HttpServiceMethod 中的invoke方法
  @Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

Retrofit的动态代理通过invoke最终调用loadServiceMethod(method).invoke(args)为我们构造一个OkHttpCall,所以可想而知,每一个请求都会创建一个OkHttpCall,它就是用来完成网络请求的。我们接口中所看到的Call就是OkHttpCall。

final class OkHttpCall<T> implements Call<T> {

  ...    

  @Override
  public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(callback, "callback == null");
    
    ...

    call.enqueue(
        new okhttp3.Callback() {
          @Override
          public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
            Response<T> response;
            try {
              response = parseResponse(rawResponse);
            } catch (Throwable e) {
              throwIfFatal(e);
              callFailure(e);
              return;
            }

            try {
              callback.onResponse(OkHttpCall.this, response);
            } catch (Throwable t) {
              throwIfFatal(t);
              t.printStackTrace(); // TODO this is not great
            }
          }

          @Override
          public void onFailure(okhttp3.Call call, IOException e) {
            callFailure(e);
          }

          private void callFailure(Throwable e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              throwIfFatal(t);
              t.printStackTrace(); // TODO this is not great
            }
          }
        });
  }

  ...

  @Override
  public Response<T> execute() throws IOException {
    okhttp3.Call call;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = getRawCall();
    }

    if (canceled) {
      call.cancel();
    }

    return parseResponse(call.execute());
  }

  ... 
  
  }
}

当我们发送同步请求则会调用OkHttpCall的execute方法,其内部最终也是调用了enqueue方法来实现的。其最终parseResponse来解析返回的响应体。

    //parseResponse 中的部分代码
    try {
      T body = responseConverter.convert(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }

这里的responseConverter即是我们所添加的数据转换器,而每个数据转换器则会在其内部重写convert来实现数据的转换,比如Json数据转换,其GsonResponseBodyConverter中的convert方法如下:

  @Override
  public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      T result = adapter.read(jsonReader);
      if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
        throw new JsonIOException("JSON document was not fully consumed.");
      }
      return result;
    } finally {
      value.close();
    }
  }

 四、总结

Retrofit利用Builder来创建Retrofit对象,在Retrofit中则利用动态代理创建ApiService的动态代理类,当调用ApiService中的方法进行网络请求时,InvocationHandler则会拦截并将请求方法封装成HttpServiceMethod,最终调用其invoke方法创建一个OkHttpCell来实现网络请求。值得注意的为了避免重复请求,Retrofit中使用了serviceMethodCache来缓存HttpServiceMethod。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值