Retrofit源码调用流程分析

目录

  • Retrofit的使用
    • 创建Retrofit
    • 创建Http代理对象
    • 通过代理对象得到Call对象
    • 通过OkHttpCall对象执行网络请求

Retrofit的使用

我们以网上很流行的天气预报的接口为例,模拟一个Retrofit的使用例子,首先我们需要一个定义请求的接口类WeatherService.java:

public interface WeatherService {
    @GET("/Ecalender/api/v2/weather")
    Call<WeatherData> getWeather(@Query("date") String date, @Query("citykey") String citykey);

    @GET("/Ecalender/api/v2/weather")
    Observable<WeatherData> getWeatherObservable(@Query("date") String date, @Query("citykey") String citykey);

}

WeatherService.java例举了两种不同的返回方式,下面我们使用标准的Call的返回方式举例调用过程代码,

private void getWeather() {
        retrofit = new Retrofit.Builder()
                .baseUrl("http://v.juhe.cn/calendar/day")
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build(); 
        service = retrofit.create(WeatherService.class); 
        String nowDate = new SimpleDateFormate("YYYY-MM-DD").format(new Date());
        Call<WeatherData> result = service.getWeather(nowDate, "101010100");  

        try {
            Response<WeatherData> r = result.execute();  
            WeatherData data = r.body(); 
            Log.e("David", "ResponseBody data = " + data);
            if (data != null) {
                Log.e("David", "RxLoaderCallback data = " + data.weatherinfo.desc);
                Log.e("David", "RxLoaderCallback data = " + data.result.lunarYear);
                Log.e("David", "RxLoaderCallback data = " + data.result.weekday);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Retrofit调用步骤:

  1. 通过Retrofit.Builder配置好各项参数,然后调用build()创建Retrofit对象。
  2. 将http接口文件WeatherService.class传递给Retrofit对象,然后创建WeatherService代理对象service
  3. 通过WeatherService代理service对象调用方法getWeather()得到Call对象result
  4. 通过Call对象resultexcute()方法执行http网络请求,得到返回结果Response对象r
  5. 通过Response对象rbody()方法得到我们真正需要的WeatherData对象。

创建Retrofit

首先new了一个Retrofit.Builder对象,然后配置各种参数,这里类似与setter的功能,其中参数baseUrl是必须要配置的,不然会报错。最后调用Retrofit.Builderbuild()方法生成Retrofit对象,其内部也是使用了new Retrofit()的方式创建新对象。。


  public static final class Builder {
    ......

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      ......
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
  }

创建Http代理对象

得到Retrofit对象后,通过Retrofit对象的create()方法创建Http的代理对象,

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(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);
          }
        });
  }

通过代理对象得到Call对象

当我们通过代理对象发起请求的时候会进入上面代理对象的InvocationHandler对象的invoke()方法中,然后会进入Retrofit对象的loadServiceMethod()方法:

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

在方法中,会首先判断是否有缓存ServiceMethod对象,如果有缓存,则直接返回之前缓存的ServiceMethod对象,否则调用ServiceMethod.parseAnnotations()创建新的ServiceMethod对象,并放入缓存。我们看看ServiceMethod是怎样创建新的对象的:


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

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

方法内部是通过HttpServiceMethod来创建的,我们在进入HttpServiceMethod

  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    ........
    
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
        
    ........
    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支持,所以直接返回的就是HttpServiceMethod子类CallAdated对象,注意此时我们返回的HttpServiceMethod对象创建时传入了okhttp3.Call.Factory对象,CallAdapter对象因为没有配置CallAdapter.Factory所以使用的默认,直接返回Call,后面会使用到。
承接上面的代理对象的请求调用其实是调用了我们刚刚生成的HttpServiceMethod对象的invoke()方法,

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

HttpServiceMethod对象的invoke()方法中,新建了一个OkHttpCall对象,然后通过适配方法adapt转换成需要的目标接口类型。根据我们上面的demo调用例子,也就是执行了CallAdated对象的adapt()

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

这里的CallAdapter对象因为没有配置CallAdapter.Factory所以使用的默认,直接返回Call,也就是上面第3步得到Call对象result。其实返回的也是一个OkHttpCall对象。

通过OkHttpCall对象执行网络请求

上面地4步,Call对象resultexcute()也就是发起网络请求,实际执行的是OkHttpCall对象的excute()方法

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

    synchronized (this) {
      .......

      call = rawCall;
      if (call == null) {
        try {
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException | Error e) {
          throwIfFatal(e); //  Do not assign a fatal error to creationFailure.
          creationFailure = e;
          throw e;
        }
      }
    }

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

    return parseResponse(call.execute());
  }

  private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

里面通过createRawCall()方法调用了OkHttpClientnewCall()创建了一个RealCall对象:

  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

然后OkHttpCall对象的excute()方法最后一行,先调用excute()方法执行网络请求。再跟进去就是OkHttp的网络请求细节了,所以不再跟进。执行完OkHttp的网络请求后,胡调用parseResponse()方法对返回结果进行处理。

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    ......

    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
      T body = responseConverter.convert(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      .......
    }
  }

可以看到请求成功后,会将返回成功body转换成目标类型之后放入Retrofit中的Responsebody。所以我们上面在第5步的时候是通过Response对象rbody()方法得到我们真正需要的WeatherData对象。

由于个人水平可能有限,如果上述博文有不正确的地方,欢迎大家指正

你可能感兴趣的:(源码,Retrofit,java,http,经验分享)