Retrofit基本使用和源码分析

本文详细介绍Retrofit的基本使用方法,包括定义API接口、初始化Retrofit及创建API实例等步骤,并深入剖析Retrofit的工作原理,涉及动态代理、适配器模式、建造者模式等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


官网:https://square.github.io/retrofit/
参考:https://blog.youkuaiyun.com/lmj623565791/article/details/51304204

1.基本使用

(1)定义一个API接口

public interface GitHubService {  
    @GET("users/{user}/repos")  
    Call<List<Repo>> listRepos(@Path("user")  String user);  
}

(2)初始化一个Retrofit,创建API接口的实例

  Retrofit retrofit = new Retrofit.Builder()  
                    .baseUrl("https://api.github.com/")  
                    .build();  
  GitHubService service = retrofit.create(GitHubService.class);

(3)调用具体的接口方法

  Call<List<Repo>> repos = service.listRepos("octocat");  
    repos.enqueue(new Callback<List<Repo>>() {  
        @Override  
      public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {  
      
      }  
      @Override  
      public void onFailure(Call<List<Repo>> call, Throwable t) {  
      
      }  
  });

2.基本API介绍

(1)@GET:get请求,参数是接口地址,和创建Retrofit时传入的baseUrl一起组成完整的请求地址
(2)@Path:以参数的形式动态组成接口地址

 @GET("users/{user}/repos")  
 Call<List<Repo>> listRepos(@Path("user") String user);  

(3)@Query:get请求的参数

@GET("group/{id}/users")  
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);

(4)@POST:post请求,参数是接口地址,和创建Retrofit时传入的baseUrl一起组成完整的请求地址

@POST("users/new")  
Call<User> createUser(@Body User user)

(5)@Body:post请求的入参

@POST("users/new")  
Call<User> createUser(@Body User user)

(6)@FormUrlEncoded,@Field:表单形式请求

@FormUrlEncoded  
@POST("user/edit")  
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);

(7)@Multipart,@Part:文件上传,多个请求体

@Multipart  
@PUT("user/photo")  
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);

(8)@Headers,@Header,@HeaderMap:请求头

@Headers("Cache-Control: max-age=640000")  
@GET("widget/list")  
Call<List<Widget>> widgetList();
    
@Headers({  
    "Accept: application/vnd.github.v3.full+json",  
    "User-Agent: Retrofit-Sample-App"})  
@GET("users/{username}")  
Call<User> getUser(@Path("username") String username);
    
@GET("user")  
Call<User> getUser(@Header("Authorization") String authorization)
    
@GET("user")  
Call<User> getUser(@HeaderMap Map<String, String> headers)

(9)addConverterFactory:可以对请求体和返回参数进行处理,比如请求格式都是json就可以使用GsonConverterFactory

Retrofit retrofit = new Retrofit.Builder()  
                .baseUrl("https://api.github.com")  
                .addConverterFactory(GsonConverterFactory.create())  
                .build();  
GitHubService service = retrofit.create(GitHubService.class);

除了json还支持其他格式

  • [Gson]:  `com.squareup.retrofit2:converter-gson`
  • [Jackson]:  `com.squareup.retrofit2:converter-jackson`
  • [Moshi]:  `com.squareup.retrofit2:converter-moshi`
  • [Protobuf]:  `com.squareup.retrofit2:converter-protobuf`
  • [Wire]:  `com.squareup.retrofit2:converter-wire`
  • [Simple XML]:  `com.squareup.retrofit2:converter-simplexml`
  • Scalars (primitives, boxed, and String):  `com.squareup.retrofit2:converter-scalars`

注意:用到哪个必须先引用相应的库

3.源码初步解析

从基本使用方法进行分析,下面是个人绘制的一个流程图,结合流程图来分析会更直观

Retrofit retrofit = new Retrofit.Builder()  
                    .baseUrl("https://api.github.com/")  
                    .build();  
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat");  
repos.enqueue(new Callback<List<Repo>>() {  
    @Override  
    public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {  
      
    }  
    @Override  
    public void onFailure(Call<List<Repo>> call, Throwable t) {  
      
    }  
});

1.创建Retrofit

(1)new Retrofit.Builder()

这个方法主要是创建了Platform

public Builder() {
    this(Platform.get());
}

具体创建代码如下:

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }

我们这里只讨论Android平台,可以看下Android这个类里面都包含了些什么

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

  可以看到这里提供了一个默认执行器MainThreadExecutor和网络请求适配器ExecutorCallAdapterFactory

(2).build()

看下Retrofit创建的具体代码

    public Retrofit build() {
      //网络请求地址
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //Okhttp请求
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      //执行者
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        //如果为空取之前platform创建的
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      //网络请求适配器列表
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      //添加默认的适配器,也是从platform获取的
      callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      //转换器列表
      List<Converter.Factory> converterFactories =
          new ArrayList<>(1 + this.converterFactories.size());

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

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

这里构建了很多重要的参数

  1. okhttp3.Call.Factory:用于okhttp请求,我们都清楚retrofit真正网络请求部分是通过okhttp实现的
  2. HttpUrl:请求地址,由baseUrl传入
  3. List<Converter.Factory>:转换器列表
  4. List<CallAdapter.Factory>:适配器列表
  5. Executor:执行者
  6. validateEagerly(Boolean):目前还不清楚有什么用

2.创建API接口的实例retrofit.create()方法

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

          @Override public 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);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

这里使用了Java动态代理的方法,简单来理解就是动态代理额外帮我们处理了很多事情,这里就把接口的方法转换成具体的请求,其中最重要的是最后三句话,下面一一进行分析。

(1)loadServiceMethod(method),创建ServiceMethod

    public ServiceMethod build() {
      //创建适配器,会遍历之前的适配器列表
      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);
      }

      if (httpMethod == null) {
        throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }

      if (!hasBody) {
        if (isMultipart) {
          throw methodError(
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        if (isFormEncoded) {
          throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }

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

      if (relativeUrl == null && !gotUrl) {
        throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError("Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError("Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError("Multipart method must contain at least one @Part.");
      }

      return new ServiceMethod<>(this);
    }

上面的代码主要做了以下几点:

  1. 创建适配器,遍历Retrofit里的适配器列表,成功就返回,所以定义适配器的顺序很重要,不过目前适配器应该比较少自己定义主要还是结合RxJava的RxJavaCallAdapterFactory使用
  2. 创建转换器,遍历Retrofit里的转换器列表,也是成功就返回
  3. 处理请求参数

(2)new OkHttpCall<>(serviceMethod, args)

初始化OkHttpCall,代码比较简单就不贴出来了

(3)serviceMethod.adapt(okHttpCall)

调用适配器的adapt方法,适配器在创建ServiceMethod中已经定义了

3.网络请求部分

这里只分析异步请求,Call.enqueue方法,实际调用的是OkHttpCall的enqueue方法

  @Override public void enqueue(final Callback<T> callback) {
    checkNotNull(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 == null) {
        try {
          //创建了okhttp,主要请求也是通过okhttp实现的
          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) {
          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();
        }
      }
    });
  }
  1. 创建了OkHttp.Call
  2. 调用OkHttp的请求方法
  3. 使用转换器对返回值进行处理
  4. 将结果进行回调

4.总结

  • Retrofit是一个优秀的第三方框架,使用了很多设计模式对代码进行封装,解耦,建造者模式,适配者模式,动态代理,工厂模式,策略模式等,很值得我们学习
  • 用户可以使用addConverterFactory和addCallAdapterFactory对代码进行定制化的处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值