初探retrofit网络请求框架

初探retrofit网络请求框架

retrofit简介

retrofit是由square公司的大神开发的一个网络请求适配器框架,这个框架简化了对okhttp的使用,它将一个基本的Java接口通过动态代理的方式翻译成一个HTTP请求,并通过OkHttp去发送请求。此外它还具有强大的可扩展性,支持各种格式转换以及RxJava。本文是基于Retrofit 2.9.0 版本去分析的。

retrofit的简单使用

这里我们只是展示一下retrofit的简单使用,主要函数为我们分析源码提供入口

//创建接口服务
interface GitHubService {
    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
}


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

	//发起网络请求
    Call<List<Repo>> repos = service.listRepos("你的github账户");
  	repos.enqueue(new Callback<List<Repo>>() {
                    @Override
                    public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
                        Log.i("guojingbu", "onResponse: 成功" + new Gson().toJson(response.body()));
                        Log.i("guojingbu","thread = "+Thread.currentThread().getName());
                    }

                    @Override
                    public void onFailure(Call<List<Repo>> call, Throwable t) {
                        Log.i("guojingbu", "onResponse: 失败");
                    }
                });

关键类说明

Retrofit:retrofit框架的总的配置入口,最关键的方法是create方法能够体现retrofit框架的整体结构

OkHttpCall:主要负责的是构建并代理okhttp的call对象进行网络请求以及结果的解析然后回调出去。

CallAdapter:主要是用来处理把okhttp请求回来的回调切换到主线程执行,但它不仅仅是单纯的做线程切换他还可以适配rxjava,以及对kotlin协程调用的支持等

ParameterHandler:这个类主要是对我们定义的请求结构的一些参数的处理类

ExecutorCallbackCall:主要是把okhttp请求结果的子线程回调切换到主线程

retrofit 源码分析

  public <T> T create(final Class<T> 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 {
					//省略...
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

Platform.get()这个方法主要是用户获取平台信息的retrofit根据不同的平台会有不同的处理,这里我们关注一下,下面分析retrofit切换线程的时候会用到。

create()方法是通过动态代理方式来创建我们请求接口的代理类,然后通过loadServiceMethod(method)加载我们创建的请求接口方法,loadServiceMethod这个方法的主要逻辑是利用map集合缓存我们的请求接口方法提高性能。

  ServiceMethod<?> loadServiceMethod(Method method) {
		//...省略缓存相关的代码
        result = ServiceMethod.parseAnnotations(this, method);
        //....省略缓存相关的代码
      }
    }
    return result;
  }

这一段代码我们主要关注parseAnnotations方法,这个方法主要解析我们定义的请求接口的注解信息和方法信息。最终它会调到HttpServiceMethod类中的parseAnnotations()方法。

  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
	//...省略一些与切换线程无关的和类型参数校验的逻辑
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
   //...
  }

在这个方法中我们可以看到一个CallAdapter类,那这个类是什么呢?我们进入createCallAdapter()方法看一下

  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
		//...
      return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
   		//...
  }

它里面调用的是retrofit中的callAdapter()方法,我们一直跟下去发现它会调用Retrofit类的nextCallAdapter()方法,我们来看一下这个方法做了什么

  public CallAdapter<?, ?> nextCallAdapter(
      @Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
    Objects.requireNonNull(returnType, "returnType == null");
    Objects.requireNonNull(annotations, "annotations == null");

    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
       //注意这个一行代码下面会用到
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
	//...省略一些处理异常的代码
  }

从这个方法可以看出它是从callAdapterFactories这个List的集合中遍历去取CallAdapter,那么callAdapterFactories这个list集合是在哪初始化的呢?通过我们查找发现是在Retrofit采用build模式,我们来看一下它的build方法

    public Retrofit build() {
    
		//...省略一些异常判断
      // 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));
		//...省略一些convert相关的代码,这里我们暂不分析.
      return new Retrofit(
          callFactory,
          baseUrl,
          unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories),
          callbackExecutor,
          validateEagerly);
    }

从这一段代码中可以看出它是调用了platform中的defaultCallAdapterFactories()方法来初始化的,跟进去发现它会创建一个DefaultCallAdapterFactory工厂对象。这个类中主要关注一下它的get()方法

  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
	//...省略一些类型的判断逻辑
    final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;

    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }

      @Override
      public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

在这个get方法中我们可以看到有一个CallAdapter匿名内部类的实现,在adapt中会返回一个ExecutorCallbackCall对象,这个类就是我们要找的线程切换相关的类了,这个类实现了是retrofit的Call接口。

  static final class ExecutorCallbackCall<T> implements Call<T> {
	//...省略一些不相关的代码
    @Override
    public void enqueue(final Callback<T> callback) {
      Objects.requireNonNull(callback, "callback == null");

      delegate.enqueue(
          new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
              callbackExecutor.execute(
                  () -> {
                    if (delegate.isCanceled()) {
                      // Emulate OkHttp's behavior of throwing/delivering an IOException on
                      // cancellation.
                      callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                    } else {
                      callback.onResponse(ExecutorCallbackCall.this, response);
                    }
                  });
            }

            @Override
            public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
          });
    }
      	//...省略一些不相关的代码
  }

通过这一段代码我们就会发现他是通过callbackExecutor这个执行器来切换线程的。那这个参数是从哪来的呢?其实是在我们调用retrofit的build方法传进来的那我们在来看一下retrofit的build方法中callbackExecutor是怎么得到的。

    public Retrofit build() {
	//...省略不相关的代码
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
       //...省略不相关的代码
    }

一层一层跟进platform.defaultCallbackExecutor()这个方法,会发现最终会调用Android的这个实现类的defaultCallbackExecutor()方法。最终通过主线程的Handler来把请求的回调切换到主线程来执行。

  static final class Android extends Platform {
     
    @Override
    public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
     //...省略无关代码
    static final class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override
      public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

以上就是retrofit是怎么切换的线程的流程。

接下来我们再来分析一下retrofit是怎么调用okhttp进行网络请求的。这里其实我们只需要关注一下retrofit的Call接口的enqueue()方法。这里我们知道retrofit的Call是一个接口,那么我应该看哪个实现类呢?通过上面的分析我们就能确定我们应该看OkHttpCall这个实现类的enqueue()方法

  @Override
  public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(callback, "callback == null");

    okhttp3.Call call;
		//...
		
          call = rawCall = createRawCall();
		//...

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

在这个方法中我们可以看到调用了createRawCall()方法,这个方法主要是构建真实用户网络请求的okhttp的call对象,

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

我们往上追踪代码你会发现上面代码中的callFactory其实就是OkHttpClient如果我们在构建retrofit时候不传OkHttpClient它会默认创建一个,这时候通过okhttpclient的newCall()我们就会得到一个真正用于网络请求的okhttp的Call对象。在上面enqueue方法中的callback回调其实并不一定是我们使用retrofit的传进来的回调callback,有可能是我们通过CallAdapter适配切换线程后返回的回调函数callback。

至于数据的解析这个其实就是我们在创建Retrofit对象时设置的GsonConverterFactory这个类通过responseBodyConverter()创建了一个GsonResponseBodyConverter的类,这个类中有一个convert的方法负责把请求回来的数据转为你想要的的类型。这里我们就不再分析了,大家可以自行了解。

总结

retrofit这个框架整个结构还是相对简单的,但是如果深入到细节还是比较复杂的,这篇文章我们主要看了下retrofit的整体结构,具体实现还需要再研究研究。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值