在Android开发过程中,除了Android自带的一些像HttpUrlConnection这些网络请求框架之外呢,常常会会用到的一些开源框架像OkHttp、Retroift等,OkHttp是我们最常用到的一种,它支持同步和异步两种请求方式,内部封装线程池等等优点;本节介绍另一个网络请求框架Retrofit,在它内部还是实现了OkHttp,但是比OkHttp的性能更好,除了多平台的适配性,还通过注解来封装了请求接口url。

1.Retrofit的导入

com.squareup.retrofit2:retrofit:2.7.1

将这个Retrofit的依赖地址导入。

2.接口注解
在开篇我就提到了,Retrofit是通过注解来封装接口,通过注解封装的接口实例,在使用Retrofit的时候,通过建造者模式创建的Retrofit对象,调用它的create方法就可以得到一个接口的实例,在这个create方法内部,就是通过动态代理模式来完成的。

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);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

上述代码就是Retrofit的create方法的源码,这个方法最终return了一个动态代理对象,就是Proxy.newProxyInstance(...,...,...)这个方法,其中传入的三个参数,分别是第一个参数是类加载器,在create方法中传入的是 Class<T> service就是获取这个接口类的类加载器,第二个参数是一个class数组,类似于占位符,传入的就是在create方法中传入的service,第三个参数是InvocationHandler(),这是一个接口,会重写里面的invoke方法

public interface InvocationHandler {
    Object invoke(Object var1, Method var2, Object[] var3) throws Throwable;
}

create方法真正执行的就是invoke方法中执行的代码;在invoke方法中,有一个 比较重要的代码就是return loadServiceMethod(method).invoke(args != null ? args : emptyArgs); 其中loadServiceMethod(method).invoke就是真正发起网络请求的方法。

ServiceMethod<?> `loadServiceMethod`(Method method) {
 	//注意这里,当去解析注解的时候,首先会去缓存中查询
 	//是否解析过这个请求,如果解析过,那么就直接去缓存中取出解解析结果。
 	**//缓存都是保存在ConcurrentHashMap中**
    ServiceMethod<?> result = serviceMethodCache.get(method);
    //result不为空
    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;
  }

从代码中可以看出,loadServiceMethodServiceMethod的一个方法,这个方法中传入一个Method对象,返回了一个result对象(ServiceMethod.parseAnnotations(this, method);),这个result对象其实就是ServiceMethod解析接口中的注解。

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(method,
          "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

ServiceMethodparseAnnotations方法中,首先是创建了一个RequestFactory 对象,在这个对象也有一个parseAnnotations方法,

static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }

在返回的build方法中,其实就是获取注解中的信息,调用parseMethodAnnotation方法,获取注解中的GET信息,其实RequestFactory 就是将注解中的信息拼接成网络请求的url字符串。

private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
      } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      } else if (annotation instanceof retrofit2.http.Headers) {
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
        if (headersToParse.length == 0) {
          throw methodError(method, "@Headers annotation is empty.");
        }
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }

从代码中可以看出,在ServiceMethod.parseAnnotations(this, method);中,真正是由HttpServiceMethodServiceMethod的子类)去执行invoke方法,发起网络请求。

从头开始我们先串一下:当我们创建一个Retrofit对象的时候,我们通过调用Retrofit对象的create方法,最终得到一个接口的实例;那么在create方法内部中,使用的是动态代理的设计模式,最终返回的是一个动态代理对象,当中核心方法就是InvocationHandler()接口的invoke方法,在这个方法中,最重要的一个方法就是loadServiceMethod,这个方法是ServiceMethod类的方法,通过执行ServiceMethod类的parseAnnotations方法得到一个ServiceMethod对象,其实真正执行parseAnnotations方法的,是ServiceMethod的一个子类HttpServiceMethod执行的,也就是说loadServiceMethod最终返回的是一个HttpServiceMethod对象,然后执行了invoke方法,也就是HttpServiceMethod的invoke方法。

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

上述代码是HttpServiceMethod中的invoke方法。

在invoke方法中,首先创建一个OkHttpCall对象,然后调用CallAdapter的adapt方法,返回一个适配接口类的Call对象。也就是说在创建成代理对象之后,通过调用其中的方法就返回了一个适配该接口类型的call对象。

@Override protected Object adapt(Call<ResponseT> call, Object[] args) {
      call = callAdapter.adapt(call);

      //noinspection unchecked Checked by reflection inside RequestFactory.
      Continuation<Response<ResponseT>> continuation =
          (Continuation<Response<ResponseT>>) args[args.length - 1];

      // See SuspendForBody for explanation about this try/catch.
      try {
        return KotlinExtensions.awaitResponse(call, continuation);
      } catch (Exception e) {
        return KotlinExtensions.suspendAndThrow(e, continuation);
      }
    }

3.动态代理模式
在上一节提到了,Retrofit的create方法中使用到了动态代理模式,我们的网络请求是通过注解接口的方式实现的,而且对于动态代理模式来说,只支持接口的形式。