关于Retrofit2.0源码的学习和理解
2016-12-20 12:21
591 查看
今年4月初,刚接触到RxJava、Retrofit等框架的时候,当时也是一头楞,因为我以前的项目中都是采用MVP加上Volley请求框架的结构。使用Retrofit开源框架搭建项目这个在网络上已经有很多很好的介绍了,在这里就不去探讨怎么使用。之所以要去写源码的实现,一方面呢是因为最近研读了下,对Retrofit有了一些了解,主要是另一个方面,写一写博客(当写笔记吧),一来理清下思路,二来相当于做个笔记,方便后面复习加深下印象。为了能更加清晰的分析Retrofit源码,我还是单独的写个工程,很简单。好嘞!废话不多说了,开始我们的Retrofit2.0源码理解之路吧!
1.简单配置Retrofit2.0
在app项目下的build.gradle中添加:
编写一个实体类:
编写interfice类
最后去构建Retrofit
2.源码分析
从构建Retrofit看起吧:MainActivity --> build() [ MainActivity中创建Retrofit最后面的build()方法,下文类似 ]
这里是创造者模式创建一个Retrofit,具体的代码是:
从上到下看来:(1)对baseUrl做了空判断处理。(2)创建OkHttpClient()对象,这个是可以自己在new Retrofit时添加进来的,如果没有配置,默认使用OkHttpClient。(3)Executor线程执行者:在Builder这个class的构造函数中有this(Platform.get()),Platform这个类通过Java反射,判断了当前的平台,我们直接看findPlatform()中的Android()方法,
接着看 MainActivity -->retrofit.create(IRequestInter.class);点击create可以看见源码:
(3)serviceMethod.callAdapter.adapt(okHttpCall):
这里的callAdapter就是上面serviceMethod.build()中createCallAdapter()返回的,而createCallAdapter最终也是通过ExecutorCallAdapterFactory中get()方法返回ExecutorCallbackCall类:
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 f 4000 rom 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动态代理使用得很精髓,包括平台的判断创建线程执行的地方等等,看的过程好痛苦,但是看通了就豁然开朗了很多,但愿这对看这篇博客的朋友有一点帮助。最后谢谢大家支持!
相关文章推荐
- 关于共同学习.NET 2.0的想法
- 关于正在学习的一个项目的理解(1)
- 好书推荐——关于学习Linux的经典书籍 (深入理解Linux内核、Linux设备驱动程序等)
- 关于学习Linux的经典书籍 (深入理解Linux内核、Linux设备驱动程序等) .
- 关于学习Linux的经典书籍 (深入理解Linux内核、Linux设备驱动程序等)
- XML学习笔记(一):关于字符编码的理解
- 关于学习Linux的经典书籍 (深入理解Linux内核、Linux设备驱动程序等)
- 关于编程的理解-【学习札记】
- 关于linux里pg command 命令的简单理解——学习笔记
- 关于学习Linux的经典书籍 (深入理解Linux内核、Linux设备驱动程序等)
- 关于CLR 2.0中托管泛型的理解
- 关于asp.net 2.0 入门学习之“GlobalResources与Callback问题”的笔记
- 关于asp.net 2.0 入门学习之“GlobalResources与Callback问题”的笔记
- us/os ii 学习笔记 20100421 关于os的一点宏观理解
- 关于学习C/C++的几点理解
- 关于T-SQL 存储过程的学习!!!(加深理解)
- WAP学习(2)--关于WAP 2.0
- 关于通过.NET Framework 2.0 中 SqlDataSource 控件 Select,Update,Delete,Insert 接口调用 存储过程 的粗浅理解。
- 关于学习Linux的经典书籍 (深入理解Linux内核、Linux设备驱动程序等)
- 关于学习Linux的经典书籍 (深入理解Linux内核、Linux设备驱动程序等)