开发者

Retrofit 创建网络请求接口实例过程

开发者 https://www.devze.com 2022-12-20 10:19 出处:网络 作者: 阿健叔
目录Retrofit 基本使用Retrofit构建过程创建网络请求接口实例过程跟踪 loadServiceMethod执行请求过程总结Retrofit 基本使用
目录
  • Retrofit 基本使用
  • Retrofit构建过程
  • 创建网络请求接口实例过程
    • 跟踪 loadServiceMethod
  • 执行请求过程
    • 总结

      Retrofit 基本使用

      implementation 'com.squareup.retrofit2:retrofit:2.9.0'
      implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
      
      interface NetApi {
          @GET("/hotkey/json")
          fun getHotKey(): Call<Response>
          companion object {
              private const val BASE_URL = "https://www.wanandroid.com/"
              fun createApi(): NetApi =
                  Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create())
                      .build().create(NetApi::class.Java)
          }
      }
      data class HotWords(
          val id: String,
          val name: String,
      )
      data class Response(
          val errorCode: Int,
          val errorMsg: String,
          val data: List<HotWords>
      )
      
      NetApi.createApi().getHotKey().enqueue(object : Callback<Response> {
          override fun onResponse(call: Call<Response>, response: retrofit2.Response<Response>) {
              Log.i(tag, "onResponse: ${response.body()?.data}")
          }
          override fun onFailure(call: Call<Response>, t: Throwable) {
              Log.i(tag, "onFailure: ${t.message}")
          }
      })
      

      这样一个基本的网络请求就搞定了,使用很简洁,正是因为其内部使用了大量的设计模式和优秀的架构设计,才得以使其如此方便地进行网络请求,下面来一起瞧瞧 Retrofit 的源码吧~

      Retrofit构建过程

      使用了建造者模式通过内部静态类 Builder 构建一个 Retrofit 实例,这里列出了部分方法,其他类似。

      public static final class Builder {
          private final Platform platform;
          // 网络请求工厂,工厂方法模式
          private @Nullable okhttp3.Call.Factory callFactory;
          // 网络请求地址
          private @Nullable HttpUrl baseUrl;
          // 数据转换器工厂的集合
          private final List<Converter.Factory> converterFactories = new ArrayList<>();
          // 网络请求适配器工厂的集合,默认是 ExecutorCallAdapterFactory
          private final List<CallAdapter.Factory> callAdapterFactories = new ArrayLilmMjvmst<>();
          // 回调方法执行器,用于切换线程
          private @Nullable Executor callbackExecutor;
          // 一个开关,为 true 则会缓存创建的 ServiceMethod
          private boolean validateEjavascriptagerly;
          ...
          public Builder baseUrl(String baseUrl) {
            Objects.requireNonNull(baseUrl, "baseUrl == null");
            return baseUrl(HttpUrl.get(baseUrl));
          }
          public Builder baseUrl(HttpUrl baseUrl) {
          开发者_JAVA入门  Objects.requireNonNull(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;
          }
          // 将一个含有 Gson 对象实例的 GsonConverterFactory 放入数据转换器工厂
          public Builder addConverterFactory(Converter.Factory factory) {
            converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
            return this;
          }
          ...
       }
      

      通过 build,我们上面 Builder 类中的参数对象都配置到了 Retrofit 对象中。

          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();
            }
            // Make a defensive copy of the adapters and add the default Call adapter.
            List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
            callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
            // Make a defensive copy of the converters.
            List<Converter.Factory> converterFactories =
                new ArrayList<>(
                    1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
            // Add the built-in converter factory first. This prevents overriding its behavior but also
            // ensures correct behavior when using converters that consume all types.
            converterFactories.add(new BuiltInConverters());
            converterFactories.addAll(this.converterFactories);
            converterFactories.addAll(platform.defaultConverterFactories());
            return new Retrofit(
                callFactory,
                baseUrl,
                unmodifiableList(converterFactories),
                unmodifiableList(callAdapterFactories),
                callbackExecutor,
                validateEagerly);
          }
      

      创建网络请求接口实例过程

      使用动态代理的方式拿到所有注解配置后,创建网络请求接口实例。

        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);
                    }
                  });
        }
      

      跟踪 loadServiceMethod

        ServiceMethod<?> loadServiceMethod(Method method) {
          ServiceMethod<?> result = serviceMethodCache.get(method);
          androidif (result != null) return result;
          synchronized (serviceMethodCache) {
            result = serviceMethodCache.get(method);
            if (result == null) {
              result = ServiceMethod.parseAnnotations(this, method);
              serviceMethodCache.put(method, result);
            }
          }
          return result;
        }
      

      parseAnnotations 解析注解配置得到 ServiceMethod,然后加入到 serviceMethodCache 缓存中,是一个 ConcurrentHashMap 。

      abstract class ServiceMethod<T> {
        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);
        }
        abstract @Nullable T invoke(Object[] args);
      }
      

      通过 RequestFactory 的 parseAnnotations 方法,解析接口方法上的注解,然后封装在 RequestFactory 对象中,将其返回,这个 RequestFactory,主要用于后续创建 OkHttp 请求所需要的 Request 对象。那后面的 HttpServiceMethod.parseAnnotations 又是干什么的呢?往下看。

      static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
          Retrofit retrofit, Method method, RequestFactory requestFactory) {
        ...
        okhttp3.Call.Factory callFactory = retrofit.callFactory;
        if (!isKotlinSuspendFunction) {
          return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
        } else if (continuationWantsResponse) {
          //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
          return (HttpServiceMethod<ResponseT, ReturnT>)
              new SuspendForResponse<>(
                  requestFactory,
                  callFactory,
                  responseConverter,
                  (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
        } else {
          //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
          return (HttpServiceMethod<ResponseT, ReturnT>)
              new SuspendForBody<>(
                  requestFactory,
                  callFactory,
                  responseConverter,
                  (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
                  continuationBodyNullable);
        }
      }
      

      如果不是 kotlin suspend 函数,使用 CallAdapted 类,如果是 kotlin suspend 函数返回类型是 Response,则使用 SuspendForReslmMjvmponse 类,其余情况使用 SuspendForBody,如 suspend 函数返回类型不是 Response 。一般情况下,我们使用的基本上是属于其余情况,我们来看下 SuspendForBody 类

      static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
        private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
        private final boolean isNullable;
        ...
        @Override
        protected Object adapt(Call<ResponseT> call, Object[] args) {
          call = callAdapter.adapt(call);
          Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
          try {
            return isNullable
                ? KotlinExtensions.awaitNullable(call, continuation)
                : KotlinExtensions.await(call, continuation);
          } catch (Exception e) {
            return KotlinExtensions.suspendAndThrow(e, continuation);
          }
        }
      }
      

      跟进 KotlinExtensions.awaitNullable,我们可以看到 SuspendForBody 会将 Response.body 作为协程挂起点的返回值。

      suspend fun <T : Any> Call<T?>.await(): T? {
        return suspendCancellableCoroutine { continuation ->
          //协程取消是调用 cancel
          continuation.invokeOnCancellation {
            cancel()
          }
          enqueue(object : Callback<T?> {
            override fun onResponse(call: Call<T?>, response: Response<T?>) {
              if (response.isSuccessful) {
                //继续执行相应的协程,将 response.body 作为最后一个挂起点的返回值。
                continuation.resume(response.body())
              } else {
                continuation.resumeWithException(HttpException(response))
              }
            }
            override fun onFailure(call: Call<T?>, t: Throwable) {
              continuation.resumeWithException(t)
            }
          })
        }
      }
      

      执行请求过程

        public void enqueue(final Callback<T> callback) {
          Objects.requireNonNull(callback, "callback == null");
          okhttp3.Call call;
          Throwable failure;
          synchronized (this) {
            if (executed) throw new IllegalStateException("Already executed.");
            executed = true;
            call = rawCall;
            failure = creationFailure;
            if (call == null && failure ==php null) {
              try {
                // 创建 OkHttp 的 Call 对象
                call = rawCall = createRawCall();
              } catch (Throwable t) {
                throwIfFatal(t);
                failure = creationFailure = t;
              }
            }
          }
          if (failure != null) {
            callback.onFailure(this, failure);
            return;
          }
          if (canceled) {
            call.cancel();
          }
          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
                  }
                }
              });
        }
      
        Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
          ResponseBody rawBody = rawResponse.body();
          // Remove the body's source (the only stateful object) so we can pass the response along.
          rawResponse =
              rawResponse
                  .newBuilder()
                  .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
                  .build();
          int code = rawResponse.code();
          // 根据响应返回的状态码进行处理 
          if (code < 200 || code >= 300) {
            try {
              // Buffer the entire body to avoid future I/O.
              ResponseBody bufferedBody = Utils.buffer(rawBody);
              return Response.error(bufferedBody, rawResponse);
            } finally {
              rawBody.close();
            }
          }
          if (code == 204 || code == 205) {
            rawBody.close();
            return Response.success(null, rawResponse);
          }
          //包装 RequestBody
          ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
          try {
            // 将响应体转为 Java 对象
            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;
          }
        }
      

      总结

      使用建造者模式通过 Builder 构建一个 Retrofit 实例,Builder 类中的参数对象都配置到 Retrofit 对象中,然后使用 JDK 动态代理的方式拿到所有注解配置后,创建网络请求接口实例,生成 OkHttp 请求,通过 CallAdapterFactory 找到对应的执行器,比如 RxJava2CallAdapterFactory,通过 ConverterFactory 将返回数据解析成 JavaBean,使用者只需关心请求参数,内部实现由 Retrofit 封装完成,底层请求还是基于 Okhttp 实现的。

      以上就是Retrofit 创建网络请求接口实例过程的详细内容,更多关于Retrofit 网络请求接口的资料请关注我们其它相关文章!

      0

      精彩评论

      暂无评论...
      验证码 换一张
      取 消