前言:Retrofit‌是一个非常流行的Android网络请求框架,主要用于简化HTTP请求的编写和执行。

一、使用简介

1.1 Retrofit的工作原理:

定义一个接口,并使用注解指定HTTP请求的方法、URL、参数等。通过动态代理模式,在运行时生成接口的实现类,该实现类负责发起网络请求。通过OkHttp客户端发送HTTP请求,处理响应,并通过Converter将响应数据转换为对象。支持同步和异步回调,通过CallbackAdapterFactory处理回调逻辑‌。

1.2 Retrofit使用步骤:

  • 添加依赖‌: 在项目的build.gradle文件中添加Retrofit的依赖。
  • 定义接口‌:创建一个接口,使用注解定义HTTP请求的方法和参数。
  • 创建Retrofit实例‌:通过Retrofit.Builder配置baseUrl、添加转换器等,然后创建Retrofit实例。
  • 创建接口实例‌:通过Retrofit实例创建接口的动态代理实例。
  • 发送请求‌:调用接口实例的方法发送请求,处理响应。

1.3 代码示例:

// 定义接口
public interface ApiService {
    @GET("/users/{username}")
    Call<User> getUser(@Path("username") String username);
}

// 创建Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
        .client(new OkHttpClient())
        .baseUrl("https://api.github.com/")
        .addConverterFactory(GsonConverterFactory.create())//设置数据解析器
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 添加RxJava适配器
        .build();
ApiService service = retrofit.create(ApiService.class);

// 发送请求
Call<User> userCall = service.getUser("test");
userCall.enqueue(new Callback<User>() {
    @Override
    public void onResponse(Call<User> call, Response<User> response) {
        // 处理响应数据
    }

    @Override
    public void onFailure(Call<User> call, Throwable t) {
        // 处理错误情况
    }
});

二、流程分析

3.1 流程图

在这里插入图片描述

3.2 流程讲解

1. 创建Retrofit实例;

2. 创建网络请求接口和相关属性注解;

3. 通过动态代理解析请求接口的注解,并生成网络请求对象;

4. 通过CallAdapter进行平台适配,平台包括(Android/java8/iOS);

5. 通过OkHttpCall发送网络请求;

6. 通过Converter数据转换适配器转换交易返回的数据;

7. 通过线程切换执行器切换到主线程;

三、源码分析

 Retrofit retrofit = new Retrofit.Builder()
      .baseUrl("https://github.com")
      .addConverterFactory(GsonConverterFactory.create())
      .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
      .build();

3.1、Retrofit类内部的成员变量

public final class Retrofit {
  private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>(); //网络请求缓存,如:请求方法、请求头、请求体,各种适配器等
  final okhttp3.Call.Factory callFactory; //okhttp工厂,真正发送交易的处理类
  final HttpUrl baseUrl; //请求url前半部,基地址
  final List<Converter.Factory> converterFactories; //数据转换器工厂集
  final List<CallAdapter.Factory> adapterFactories; //网络请求适配器工厂集
  final @Nullable Executor callbackExecutor; //异步请求结果线程切换执行器
  final boolean validateEagerly; //标志位、是否马上解析接口方法
...
}

3.2、Retrofit内部类Builder

public final class Retrofit {
...
  public static final class Builder {
    private final Platform platform; //适配平台,通常默认android
    private @Nullable okhttp3.Call.Factory callFactory; //okhttp网络请求工厂,默认okhttp
    private HttpUrl baseUrl; //基地址
    private final List<Converter.Factory> converterFactories = new ArrayList<>(); //数据转换器集,用于生产数据转换器,默认GsonConverterFactory
    private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>(); //网络请求适配器,如RxJava2CallAdapterFactory
    private @Nullable Executor callbackExecutor; //执行异步回调的线程切换
    private boolean validateEagerly; //是否立即解析接口注解方法

 	Builder(Platform platform) {
      this.platform = platform;
      converterFactories.add(new BuiltInConverters());//添加默认数据解析器
    }
    
    public Builder() {
      this(Platform.get());
    }
  } 
...
}

在创建Builder实例时调用的是Builder的无参构造放法,里面调用了Builder(Platform)这个构造方法,传入的是Platform.get()返回数据,这个方法是获取适配平台,默认是Android,其他平台咱们不做过多分析,直接查看Android:

class Platform {
...
  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
 
    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
 
    static class MainThreadExecutor implements Executor {
      //默认线程切换是切换到主线程
      private final Handler handler = new Handler(Looper.getMainLooper());
 
      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }
...
}

可以看到在创建Builder实例的适配平台时,将工作线程切换到了主线程,这是后面可以通过主线程回调返回请求数据的原因。
接着将会在Builder的有参构造方法中的添加Retrofit默认的数据解析器:

3.3、Builder.build()方法

public final class Retrofit {
...
  public static final class Builder {
    ...
    public Retrofit build() {
      if (baseUrl == null) { //对baseurl进行非空判断
        throw new IllegalStateException("Base URL required.");
      }
 
      //注释①
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient(); //创建okhttp客户端
      }
      //注释②
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
 
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
 
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
 
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
  }
}

注释①处,上面说过Retrofit2框架的底层发送交易其实是提交给了okhttp框架,在okhttp3源码讲解时咱们说过在okhttp中OkhttpClient在整个进程中只创建一次,所以在这里做了相关判断。

注释②处,可以看到是获取回调执行器,如果没有设置回调执行器,就创建一个默认的主线程回调执行器。

最后调用Retrofit的构造方法,创建一个Retrofit实例。可以看到整个创建Retrofit过程中,通过构建者模式来执行一系列初始化和对象的创建。

3.4、retrofit.create()

调用retrofit.create(NetService.class),这个方法是Retrofit的核心,内部采用动态代理,将咱们自定义的网络请求接口转换成一个ServiceMethod对象,ServiceMethod就是咱们Retrofit中的具体请求对象,里面封装了网络请求所必须的全部信息,包括请求方法、url、请求头、请求体等网络配置参数!

...
  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) { //创建retrofit实例时提到的标志位
      //注释①
      eagerlyValidateMethods(service);
    }
    //注释②
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
 
          //注释③
          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }
...

注释①处,如果提前验证的标志位为true,将会调用eagerlyValidateMethods(service)方法:

  private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method)) {
        loadServiceMethod(method);
      }
    }
  }

可以看到这个方法内部通过反射机制,来获取咱们自定义的请求接口对象类的内部方法

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

这个方法用于加载serviceMethod,一个serviceMethod对应咱们定义的网络请求接口中的一个方法。ServiceMethod的成员变量如下

final class ServiceMethod<R, T> {
 private final okhttp3.Call.Factory callFactory; //okhttp call的工厂
 private final CallAdapter<R, T> callAdapter; //网络请求适配器

 private final HttpUrl baseUrl; //基地址
 private final Converter<ResponseBody, R> responseConverter; //数据转换器
 private final String httpMethod; //网络请求方法
 private final String relativeUrl; //网络请求相对地址,和基地址拼接成完整地址
 private final Headers headers; //请求头
 private final MediaType contentType; //请求体
 private final boolean hasBody; 
 private final boolean isFormEncoded;
 private final boolean isMultipart;
 private final ParameterHandler<?>[] parameterHandlers; //方法参数处理器
 ...
}

ServiceMrthod中维护了okhttp用于网络请求的Call工厂,用于生产Call,并且ServiceMrthod声明了网络请求所需元素的所有基本信息。看ServiceMrthod的上面源码发现,它是通过构建者模式来创建实例

查看ServiceMrthod的Builder内部类:

final class ServiceMethod<R, T> {
    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit; //retrofit实例
      this.method = method; //网络请求方法
      this.methodAnnotations = method.getAnnotations(); //网络请求方法的注解
      this.parameterTypes = method.getGenericParameterTypes(); //获取网络请求方法里的注解的类型
      this.parameterAnnotationsArray = method.getParameterAnnotations(); //获取网络请求方法里的注解的内容
    }
    
  static final class Builder<T, R> {
  ...
    public ServiceMethod build() {
      //注释①:主要是根据网络请求接口中的方法和方法内注解的类型,从retrofit中获取网络请求接口适配器。
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      //注释②:创建网络请求返回数据转换器
      responseConverter = createResponseConverter();
 
      //注释③ :是解析请求接口中的所有注释。
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      
      ...
 
      //注释④:ParameterHandler类就是接口参数解析器,
      // 主要是解析网络请求接口的参数,包括自定义请求接口参数和配置的请求参数
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        if (Utils.hasUnresolvableType(parameterType)) {
          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
              parameterType);
        }
 
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }
 
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

      return new ServiceMethod<>(this);
    }
}   
...
}

loadServiceMethod(),这个方法主要是创建并加载ServiceMehod,用于解析网络请求接口参数、网络请求适配器、response数据解析器等工作。

3.5、创建OkHttpCall对象

OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

OkHttpCall就是对okhttp的call对象的封装,咱们现在看OkHttpCall的实现:

final class OkHttpCall<T> implements Call<T> {
...
  @GuardedBy("this")
  private @Nullable okhttp3.Call rawCall;
  ...
 
  @Override public void enqueue(final Callback<T> callback) {
    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) {
          callFailure(e);
          return;
        }
 
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
 
      @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) {
          t.printStackTrace();
        }
      }
    });
 
  ...
 
  @Override public Response<T> execute() throws IOException {
    okhttp3.Call call;
 
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
 
      if (creationFailure != null) {
        if (creationFailure instanceof IOException) {
          throw (IOException) creationFailure;
        } else if (creationFailure instanceof RuntimeException) {
          throw (RuntimeException) creationFailure;
        } else {
          throw (Error) creationFailure;
        }
      }
 
      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());
  }
...
  }

OkHttpCall内部维护了一个okhttp3.Call rawCall的对象,接着看下面两个方法:enqueue()和execute(),可以看到内部调用的是rawCall的对应方法,也就是调用okhttp3.Call的enqueue()和execute()。

3.6、serviceMethod.adapt(okHttpCall)

这个方法很显然使用适配器模式,将某些咱们需要处理的事件,适配成其他平台可以使用的类型,并在该平台使用。这里调用serviceMethod的adapt适配方法,传入了OkHttpCall实例,并将适配对象返回。adapt()方法源码:

final class ServiceMethod<R, T> {
...
  T adapt(Call<R> call) {
    return callAdapter.adapt(call);
  }
...
}

可以看到内部调用的是callAdapter.adapter(call),而callAdapter对象实例是在loadServiceMethod()方法中调用ServiceMethod构建者模式创建实例时候创建的:

final class ServiceMethod<R, T> {
  ...
  static final class Builder<T, R> {
    ...
    CallAdapter<T, R> callAdapter;
        public ServiceMethod build() {
            ...
            callAdapter = createCallAdapter();
            ...
        }
  }
...
}

在调用callAdapter的adapter()方法,其实就是把一个个Retrofit中的Call适配成其他平台也能使用的Call类型,比如咱们栗子中使用的是RxJava2CallAdapterFactory.create()来创建了一个RxJava2CallAdapter的适配器来适配RxJava2平台,适配成RxJava2平台能使用的Call。

接下来看Retrofit的CallAdapter接口中的Rxjava2CallAdapter实现类的adapter()方法:

final class RxJava2CallAdapter implements CallAdapter<Object> {
...
  @Override public <R> Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = new CallObservable<>(call);
    Observable<?> observable;
    ...
    return observable;
  }
...
}

可以看到,该适配方法返回了一个Observable被观察者对象。所以在咱们栗子中最后创建Retrofit的Call接口的实例对象时,也就创建了一个被观察者对象。

然后,通过Retrofit的Call实现类,调用execute()方法,也就是调用okhttp3.Call的execute()方法来发送同步请求,请求结果同步返回;调用enqueue()方法,也就是调用okhttp3.Call的enqueue()方法来发送异步请求,请求结果通过Callback接口对象回调返回。

至此,有关Retrofit2的源码分析结束。

四、常见面试题

4.1 Retrofit的工作原理是什么?

Retrofit的工作原理主要包括以下几个步骤:
定义接口‌:开发者定义一个接口,并使用注解指定HTTP请求的方法、URL、参数等。
动态代理‌:通过动态代理模式,在运行时生成接口的实现类,该实现类负责发起网络请求。
请求发送‌:通过OkHttp客户端发送HTTP请求,处理响应,并通过Converter将响应数据转换为对象。
回调处理‌:支持同步和异步回调,可以通过CallbackAdapterFactory处理回调逻辑‌。

4.2 ‌Retrofit的主要优点是什么?‌

‌解耦‌:Retrofit解耦了接口定义、参数和回调,使得代码更加清晰和模块化。
灵活性‌:支持同步和异步请求,可以配置不同的HTTP客户端(如OkHttp)和反序列化工具(如Gson)。
‌高效‌:使用OkHttp作为底层网络库,提供高效的请求处理能力‌

‌4.3 Retrofit如何实现子线程切换到主线程?‌

Retrofit通过在构建Retrofit实例时添加CallbackExecutorFactory,将回调执行器设置为特定的线程池或Handler,从而实现在子线程中进行网络请求,并在主线程中处理结果‌。

4‌.4 Retrofit中的动态代理和静态代理有什么区别?‌

‌动态代理‌:在运行时动态创建代理类,适用于接口或抽象类。通过Proxy.newProxyInstance生成代理类,调用任何方法时都会被InvocationHandler拦截和处理‌。
静态代理‌:在编译时定义好的代理类,适用于具体的类。需要在代码中显式地创建代理对象‌。

4.5 Retrofit中的注解及其作用‌

‌@GET、@POST等‌:用于指定HTTP请求方法(如GET、POST)和URL。
‌@Query、@Body等‌:用于指定请求参数和请求体‌。

4.5 Retrofit用到了哪些设计模式?

  1. 创建Retrofit的方式使用的是构建者模式,对于多参数情况配置,调理更加清晰;
  2. 调用create函数,retrofit是通过Proxy.newProxyInstance 动态代理以及反射的机制生成实现类;
  3. 适配器模式:RxJava2CallAdapter实现CallAdapter用的就是适配器模式;
  4. 抽象工厂模式:抽象工厂模式的定义是为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {}

其中CallAdapter.Factory为抽象工厂,CallAdapter为工厂的产品接口,不同的CallAdapter.Factory抽象工厂创建不同的CallAdapter产品

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐