Retrofit原理分析

Retrofit2使用这篇文章中介绍过retrofit的使用,那现在我们通过源码来分析其原理。源码版本Retrofit:2.0.2

 compile 'com.squareup.retrofit2:retrofit:2.0.2'

创建Retrofit对象

首先使用了Builder模式创建出Retrofit对象:

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)  //请求地址的域名
                .addConverterFactory(GsonConverterFactory.create())//把请求返回的数据解析我们关心的格式,这里我们通过Gson来解析返回的数据
                .client(new OkHttpClient())
                .build();

创建retrofit对象时需要我们设置几个重要的数据,通过addxxx()方法来设置,域名,数据转换器。client方法可以不用设置,因为retrofit请求的任务默认交给OkHttp处理。

Retrofit框架支持了IOS,Android,Java8平台。默认的平台的Android,需要设置其他平台通过构造函数注入,Builder类中有个带参数的构造函数,如下:

 Builder(Platform platform) {
      this.platform = platform;
      converterFactories.add(new BuiltInConverters());
    }

创建接口服务代理

然后调用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, 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 serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

我们都知道动态代理的一大特点就是,可以在调用目的对象之前和之后可以做一些其它的相关操作。

首先判断,该方法是否属于Object类?直接invoke解析那个方法
: 判断是否是默认的方法?调用platform.invokeDefaultMethod方法来解析那个方法:通过ServiceMethod来解析那个方法。

创建ServiceMethod

我们去分析ServiceMethod是怎么解析那个方法的。
调用loadServiceMethod方法创建ServiceMethod对象,我们去看看:

  private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();

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

首先判断serviceMethodCache缓存是否存在该对象。如果没有通过Builder模式创建ServiceMethod对象,该对象创建出来后会缓存在serviceMethodCache对象中。

我们去看看是怎么build出来的:

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

      .......

      return new ServiceMethod<>(this);
    }

在上述代码做了三个重要的操作:

  1. 创建CallAdapter,该对象用来管理线程,在Platform类中的defaultCallAdapterFactory方法可以看出:

  CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
    if (callbackExecutor != null) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapterFactory.INSTANCE;
  }

2.创建Converter,用来把返回的数据解析成我们想要的格式。Retrofix提供很多Converter工厂,Gson,xml等
3.解析服务接口的注解。通过解析注解,封装成request对象发送请求。

创建OkHttpCall

直接new出来一个OkHttpCall对象,该对象是OkHttp的封装类,通过该类 ,把请求的任务交给OkHttp处理。

返回代理服务接口对象

生成接口服务代理对象,并返回:

 return serviceMethod.callAdapter.adapt(okHttpCall);

最后我们就可以发送请求,等待数据返回:

 Call<NewsInfo> newsInfoCall = newsServive.newsListByGetMethod(paramsMap);

        //发送异步的请求
        newsInfoCall.enqueue(new Callback<NewsInfo>() {
            @Override
            public void onResponse(Call<NewsInfo> call, Response<NewsInfo> response) {

                NewsInfo newsInfo = response.body();
                if(newsInfo.getError_code() == REQ_OK){

                    for (NewsInfo.ResultBean info : newsInfo.getResult()){
                         Log.d("tag","-----> info = " + info.toString());
                     }

                }else{
                    Log.e("tag","----> reason = " + newsInfo.getReason());

                }

            }

            @Override
            public void onFailure(Call<NewsInfo> call, Throwable t) {
                Log.e("tag","-----> error = " + t.getMessage());

            }
        });

总结整个流程:
这里写图片描述

END。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值