关于Retrofit2.0源码的学习和理解

    今年4月初,刚接触到RxJava、Retrofit等框架的时候,当时也是一头楞,因为我以前的项目中都是采用MVP加上Volley请求框架的结构。使用Retrofit开源框架搭建项目这个在网络上已经有很多很好的介绍了,在这里就不去探讨怎么使用。之所以要去写源码的实现,一方面呢是因为最近研读了下,对Retrofit有了一些了解,主要是另一个方面,写一写博客(当写笔记吧),一来理清下思路,二来相当于做个笔记,方便后面复习加深下印象。为了能更加清晰的分析Retrofit源码,我还是单独的写个工程,很简单。好嘞!废话不多说了,开始我们的Retrofit2.0源码理解之路吧!


1.简单配置Retrofit2.0

    在app项目下的build.gradle中添加:

compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.0'

    编写一个实体类:

package com.jianzou.retrofit;

/**
 * Created by JianZou on 2016/12/19.
 */

public class UserModel
{
    private String id;
    private String name;
    private String age;

    public String getId()
    {
        return id;
    }

    public void setId(String id)
    {
        this.id = id;
    }

    public String getAge()
    {
        return age;
    }

    public void setAge(String age)
    {
        this.age = age;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }
}

编写interfice类

package com.jianzou.retrofit;

import java.util.List;

import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;

/**
 * Created by JianZou on 2016/12/19.
 */

public interface IRequestInter
{
    @GET("Users/{action}")
    Call<List<UserModel>> getUsers(@Path("action") String action);
}

最后去构建Retrofit

package com.jianzou.retrofit;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class MainActivity extends AppCompatActivity
{

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //构建Retrofit
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://www.ceshi.demo/api")//URL可以修改成自己请求的公共URL部分
                .addConverterFactory(GsonConverterFactory.create())//这里使用Gson来转化返回的数据
                .build();
        /*
        根据Java动态代理,动态的获取到每个接口的方法、参数和注解,再将这些拼接成一个request(ServiceMethod.toRequest()方法);
        由OKHttp请求后返回结果,然后将返回的数据通过我们设定的GsonConverterFactory转化成Gson格式的数据;
        最后,源码中设置的OkHttpCall将返回并转化成Gson格式的数据回调给UI线程。
         */
        IRequestInter request = retrofit.create(IRequestInter.class);

        Call<List<UserModel>> call = request.getUsers("buy");

        call.enqueue(new Callback<List<UserModel>>()
                     {
                         @Override
                         public void onResponse(Call<List<UserModel>> call, Response<List<UserModel>> response)
                         {

                         }

                         @Override
                         public void onFailure(Call<List<UserModel>> call, Throwable t)
                         {

                         }
                     }

        );

    }
}
到这,简单的配置下就完了,再次声明:只是为了读源码而配置的这些,实际不能运行的哈!


2.源码分析

从构建Retrofit看起吧:MainActivity --> build() [ MainActivity中创建Retrofit最后面的build()方法,下文类似 ]

这里是创造者模式创建一个Retrofit,具体的代码是:

/**
     * Create the {@link Retrofit} instance using the configured values.
     * <p>
     * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link
     * OkHttpClient} will be created and used.
     */
    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

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

从上到下看来:(1)对baseUrl做了空判断处理。(2)创建OkHttpClient()对象,这个是可以自己在new Retrofit时添加进来的,如果没有配置,默认使用OkHttpClient。(3)Executor线程执行者:在Builder这个class的构造函数中有this(Platform.get()),Platform这个类通过Java反射,判断了当前的平台,我们直接看findPlatform()中的Android()方法,

static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      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);
      }
    }
  }
这个类默认new的是MainThreadExecutor对象,然后将这个线程放到主线程的消息队列中。通过ExecutorCallAdapterFactory中get()方法返回了final的ExecutorCallbackCall类,(4) adapterFactories,这个主要是上面call的集合,不需要关心,(5)converterFactories:这个用来将请求返回的数据进行转化以及请求中注解参数的转化。

接着看 MainActivity -->retrofit.create(IRequestInter.class);点击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);
          }
        });
  }
这里就是用到了Java的动态代理截获接口的方法,参数名等信息。我们主要的看最后几行有效代码:

(1)创建ServiceMethod:

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;
  }
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);
    }
在ServiceMethod的build方法中:createCallAdapter()返回的实际上是Retrofit Build()方法中我们add到adapterFactories中的callAdapter,callAdapter.responseType()返回的其实就是我们传进去的UserModel类型,而createResponseConverter得到的是responseConverter对象,因为我们在创建Retrofit的时候加了这么一行addConverterFactory(GsonConverterFactory.create()),所以这里返回的是GsonConverterFactory。代码的下面就是对方法和参数注解进行了解析,这里获得到很多的parameterHandler对象,最终在ServiceMethod的toRequest方法调用中,通过parameterHandler的apply方法构造一个完整的请求。

(2)创建OkHttpCall:

OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }
这一步主要是把上面创建的serviceMethod以及接口中方法的参数存在本类中。

(3)serviceMethod.callAdapter.adapt(okHttpCall):

这里的callAdapter就是上面serviceMethod.build()中createCallAdapter()返回的,而createCallAdapter最终也是通过ExecutorCallAdapterFactory中get()方法返回ExecutorCallbackCall类:

  @Override
  public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public <R> Call<R> adapt(Call<R> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              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(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

    @Override public boolean isExecuted() {
      return delegate.isExecuted();
    }

    @Override public Response<T> execute() throws IOException {
      return delegate.execute();
    }

    @Override public void cancel() {
      delegate.cancel();
    }

    @Override public boolean isCanceled() {
      return delegate.isCanceled();
    }

    @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
    @Override public Call<T> clone() {
      return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
    }

    @Override public Request request() {
      return delegate.request();
    }
  }
这个类通过delegate的enqueue去请求数据,delegate对象实质上就是serviceMethod.callAdapter.adapt(okHttpCall)这行中的okHttpCall对象,由adapt()这个方法设置进去。这里面的callbackExecutor是上面Platform类Android()方法中识别在Android平台而创建的MainThreadExecutor对象,此对象存放在了主线程的消息队列,在这里执行MainThreadExecutor通过callback回调到UI线程,从而有成功onResponse和失败onFailure两个回调。接着我们看下delegate.enqueue,实际就是okHttpCall中的enqueue:

@Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("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 {
          call = rawCall = createRawCall();
        } catch (Throwable 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)
          throws IOException {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }
这里面有这个方法createRawCall()方法:

private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }
createRawCall()返回okHttp3.Call对象,也就是用的okHttp3.Call对象来执行的请求。在createRawCall()中,通过serviceMethod.toRequest(args)得到请求的url,上面也提到了ServiceMethod的toRequest方法通过parameterHandler的apply方法构造一个完整的request,到此,一个请求的线路就说完了。下面接着看响应的内容:这里有一行response = parseResponse(rawResponse);

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();

    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
      try {
        // Buffer the entire body to avoid future I/O.
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }

    if (code == 204 || code == 205) {
      return Response.success(null, rawResponse);
    }

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      T body = serviceMethod.toResponse(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
  }
在return的地方,T body = serviceMethod.toResponse(catchingBody);

/** Builds a method return value from an HTTP response body. */
  T toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }
其实就是通过serviceMethod的toResponse将请求返回的数据用我们的converter进行转化,这个转化器就是开篇我们设置进去的GsonConverterFactory。到此整个源码分析就结束了,重新整理下:我们将页面上接口传给Retrofit,Retrofit通过Java动态代理去对接口中方法和注解进行解析,在Retrofit创建的时候,根据Java平台默认创建Executor,并将此Executor存放在主线程的消息队列,在Retrofit创建中,创建了最重要的serviceMethod类,serviceMethod类将对方法和注解进行解析拼接成请求的url,并对返回的数据做转换处理。创建的OkHttpCall对象就实质上还是用的okHttp3.Call对象去执行的请求,通过serviceMethod.toRequest(args)得到的url请求,得到数据后由serviceMethod设置的转化器解析数据。最终callback以回调的方式将数据给UI界面。总算是明朗了很多,开源框架在使用的同时,看一看实现的源码,收获很多,这里的Java动态代理使用得很精髓,包括平台的判断创建线程执行的地方等等,看的过程好痛苦,但是看通了就豁然开朗了很多,但愿这对看这篇博客的朋友有一点帮助。最后谢谢大家支持!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值