Retrofit原理分析

来源:互联网 发布:换热器软件 编辑:程序博客网 时间:2024/04/28 15:26

在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。

0 0
原创粉丝点击