Retrofit源码分析
2016-07-06 02:52
417 查看
通过一次网络请求,来分析Retrofit源码
Retrofit第三方开源库,最近在很多地方都看到有人在使用。用了之后,感觉这是一个很简洁,代码维护成本较低的开源库。
Retrofit一般会依赖OkHttp这个库,它访问网络依赖OkHttpClient,通常情况下都是:Retrofit + OkHttp一起使用的。
Retrofit也支持RxJava作为适配器工厂,Retrofit + OkHttp + RxJava 的组合也是很多开发者喜欢的。
在这里,通过Retrofit来请求一次网络,一步一步分析Retrofit内部原理与源码。
简单来说,Retrofit通过:注解 + 反射 + 动态代理。面向对象的形式来处理一次网络请求。
Retrofit让请求网络的代码变得简洁起来了,维护成本也低很多。
Retrofit让开发者只关心两个问题:
1,请求网络接口类的定义。
2,解析服务器传递过来的json生成Java Bean。
下面就从使用方式上来分析Retrofit的源码。
例如,让Retrofit来完成这样的一次网络请求,将服务器传递过来的json转化成Java Bean。
Get请求:
1,首先,生成请求网络接口类。
2,分析服务器传递过来的json生成Java Bean。
3,声明HostUrl。
4,创建OkHttpClient。
5,生成Retrofit对象,通过Retrofit对象获取到接口的实现类。
6,使用Retrofit请求网络。
7,创建自己的CallBack,简化回调参数。
使用Retrofit请求网络就是这么简单,开发者只需要把注意力放在请求网络的接口类和服务器返回的Java Bean就行了。
现在开始分析源码:
可以看到使用了接口,以注解的方式设置网络请求方式,请求参数信息。
可以看得出,Retrofit想动态的获取到注解,请求参数信息,只能通过反射的方式拿到了。
下面分析Retrofit是怎么初始化,怎么拿到这些注解信息的:
进一步查看Retrofit源码:
静态内部类,Builder
可使用链式编程,快速初始化参数
最终,以Retrofit构造器的形式生成Retrofit对象
可以看到,Retrofit获取对象的方式,是通过构造者模式。通过构造者这个静态内部类,链式编程的方式快速设置Retrofit参数,
最后将构造者设置的参数,以Retrofit构造器的形式生成Retrofit对象。
接下来,看Retrofit如何使用字节码,生成接口的实现类的。
进入create源码:
可以看到,通过动态代理的方式,生成接口的实现了。
接下来看这行代码:
loadServiceMethod方法,将接口实现类的method字段传递进去,生成一个ServieMethod对象。进入到方法里:
可以看到,method对象作为Map集合的Key,存储了起来。ServiceMethod是一个Method的包装类。
可以猜的出,ServiceMethod是Retrofit的一次网络请求的具体Java Bean对象。
Retrofit的网络请求,以对象的方式存储到Map集合serviceMethodCache中。
接来下看这行代码:
将一次网络请求的所有信息serviceMethod对象传递给了OkHttpCall,意思是这次网络请求准备交给OkHttp处理。
内部可以看到,OkHttpCall拥有一个网络请求serviceMethod
这行代码会将okHttpCall返回出去。也就是我们自定义接口,方法的返回值:
我们请求网络的时候是这样的:
在OkHttpCall里也有enqueue方法:
方法里找到:
可以看到,Retrofit里面的确是通过OkHttpClient进行网络请求的。
这个callFactory就行Retrofit外面设置的OkHttpClient对象,只是以接口的方式显示,数据跟踪可以知道。
总的来说,当我们以调用接口实现类的方法:
Retrofit会通过动态代理,获取到接口对象,method字段,再通过反射获取到method字段中的注解,请求参数,
将信息存储到serviceMethod中,一个serviceMethod就包含了一次完整请求网络所需要的数据,
Host,Uri,请求参数,请求类型都有,再通过OkHttp的方式去请求网络,获取到json,
在通过Gson转化工厂将json转化成Java Bean,回调的方式传递出去
这就是Retrofit请求网络的源码分析。
注解 + 反射 + 动态代理 ,依赖OkHttp库。
Retrofit源码分析就到这里。
2016年7月06日 02:35:16
Retrofit第三方开源库,最近在很多地方都看到有人在使用。用了之后,感觉这是一个很简洁,代码维护成本较低的开源库。
Retrofit一般会依赖OkHttp这个库,它访问网络依赖OkHttpClient,通常情况下都是:Retrofit + OkHttp一起使用的。
Retrofit也支持RxJava作为适配器工厂,Retrofit + OkHttp + RxJava 的组合也是很多开发者喜欢的。
在这里,通过Retrofit来请求一次网络,一步一步分析Retrofit内部原理与源码。
compile "com.squareup.retrofit2:retrofit:2.0.2" compile "com.squareup.retrofit2:converter-gson:2.0.2" compile 'com.squareup.okhttp3:okhttp:3.2.0'
简单来说,Retrofit通过:注解 + 反射 + 动态代理。面向对象的形式来处理一次网络请求。
Retrofit让请求网络的代码变得简洁起来了,维护成本也低很多。
Retrofit让开发者只关心两个问题:
1,请求网络接口类的定义。
2,解析服务器传递过来的json生成Java Bean。
下面就从使用方式上来分析Retrofit的源码。
例如,让Retrofit来完成这样的一次网络请求,将服务器传递过来的json转化成Java Bean。
Get请求:
https://api.douban.com/v2/fm/app_channels
1,首先,生成请求网络接口类。
public interface AppChannelsApi { @GET("v2/fm/app_channels") Call<AppChannels> getAppCannels(); }
2,分析服务器传递过来的json生成Java Bean。
public class AppChannels { private List<GroupsBean> groups; ...
3,声明HostUrl。
public class HostUrl { public static final String HOST = "https://api.douban.com/"; }
4,创建OkHttpClient。
public class HttpClient { private static OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build(); public static OkHttpClient get() { return mOkHttpClient; } }
5,生成Retrofit对象,通过Retrofit对象获取到接口的实现类。
public class AppChannelsClient { private static AppChannelsApi api; public static AppChannelsApi get() { if (api == null) { synchronized (AppChannelsClient.class) { if (null == api) { Retrofit retrofit = new Retrofit.Builder() .baseUrl(HostUrl.HOST) .client(HttpClient.get()) .addConverterFactory(GsonConverterFactory.create()) .build(); api = retrofit.create(AppChannelsApi.class); } } } return api; } }
6,使用Retrofit请求网络。
Call<AppChannels> call = AppChannelsClient.get().getAppCannels(); call.enqueue(new MyCallBack<AppChannels>() { @Override public void onSuccess(AppChannels data) { Log.i(TAG, "size:" + data.getGroups().size() + " " + data.toString()); mTextView.setText(data.toString()); } @Override public void onFailure(Call<AppChannels> call, Throwable t) { } });
7,创建自己的CallBack,简化回调参数。
public abstract class MyCallBack<T> implements Callback<T> { @Override public void onResponse(Call<T> call, Response<T> response) { T data = response.body(); if (data != null) { onSuccess(data); } else { onFailure(call, null); } } abstract public void onSuccess(T data); }
使用Retrofit请求网络就是这么简单,开发者只需要把注意力放在请求网络的接口类和服务器返回的Java Bean就行了。
现在开始分析源码:
public interface AppChannelsApi { @GET("v2/fm/app_channels") Call<AppChannels> getAppCannels(); }
可以看到使用了接口,以注解的方式设置网络请求方式,请求参数信息。
可以看得出,Retrofit想动态的获取到注解,请求参数信息,只能通过反射的方式拿到了。
下面分析Retrofit是怎么初始化,怎么拿到这些注解信息的:
public class AppChannelsClient { private static AppChannelsApi api; public static AppChannelsApi get() { if (api == null) { synchronized (AppChannelsClient.class) { if (null == api) { Retrofit retrofit = new Retrofit.Builder() .baseUrl(HostUrl.HOST) .client(HttpClient.get()) .addConverterFactory(GsonConverterFactory.create()) .build(); api = retrofit.create(AppChannelsApi.class); } } } return api; } }
进一步查看Retrofit源码:
静态内部类,Builder
public static final class Builder { private Platform platform; private okhttp3.Call.Factory callFactory; private HttpUrl baseUrl; private List<Converter.Factory> converterFactories = new ArrayList<>(); private List<CallAdapter.Factory> adapterFactories = new ArrayList<>(); private Executor callbackExecutor; private boolean validateEagerly; Builder(Platform platform) { this.platform = platform; // Add the built-in converter factory first. This prevents overriding its behavior but also // ensures correct behavior when using converters that consume all types. converterFactories.add(new BuiltInConverters()); } public Builder() { this(Platform.get()); }
可使用链式编程,快速初始化参数
public Builder client(OkHttpClient client) { return callFactory(checkNotNull(client, "client == null")); } public Builder callFactory(okhttp3.Call.Factory factory) { this.callFactory = checkNotNull(factory, "factory == null"); return this; } public Builder baseUrl(String baseUrl) { checkNotNull(baseUrl, "baseUrl == null"); HttpUrl httpUrl = HttpUrl.parse(baseUrl); if (httpUrl == null) { throw new IllegalArgumentException("Illegal URL: " + baseUrl); } return baseUrl(httpUrl); }
最终,以Retrofit构造器的形式生成Retrofit对象
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); }
public final class Retrofit { private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>(); private final okhttp3.Call.Factory callFactory; private final HttpUrl baseUrl; private final List<Converter.Factory> converterFactories; private final List<CallAdapter.Factory> adapterFactories; private final Executor callbackExecutor; private final boolean validateEagerly; Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl, List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories, Executor callbackExecutor, boolean validateEagerly) { this.callFactory = callFactory; this.baseUrl = baseUrl; this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site. this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site. this.callbackExecutor = callbackExecutor; this.validateEagerly = validateEagerly; }
可以看到,Retrofit获取对象的方式,是通过构造者模式。通过构造者这个静态内部类,链式编程的方式快速设置Retrofit参数,
最后将构造者设置的参数,以Retrofit构造器的形式生成Retrofit对象。
接下来,看Retrofit如何使用字节码,生成接口的实现类的。
api = retrofit.create(AppChannelsApi.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); } }); }
可以看到,通过动态代理的方式,生成接口的实现了。
接下来看这行代码:
ServiceMethod serviceMethod = loadServiceMethod(method); OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall);
loadServiceMethod方法,将接口实现类的method字段传递进去,生成一个ServieMethod对象。进入到方法里:
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 final class Retrofit { private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>(); final class ServiceMethod<T> { // Upper and lower characters, digits, underscores, and hyphens, starting with a character. static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*"; static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}"); static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM); final okhttp3.Call.Factory callFactory; final CallAdapter<?> callAdapter; private final HttpUrl baseUrl; private final Converter<ResponseBody, T> responseConverter; private final String httpMethod; private final String relativeUrl; private final Headers headers; private final MediaType contentType; private final boolean hasBody; private final boolean isFormEncoded; private final boolean isMultipart; private final ParameterHandler<?>[] parameterHandlers;
可以看到,method对象作为Map集合的Key,存储了起来。ServiceMethod是一个Method的包装类。
可以猜的出,ServiceMethod是Retrofit的一次网络请求的具体Java Bean对象。
Retrofit的网络请求,以对象的方式存储到Map集合serviceMethodCache中。
接来下看这行代码:
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
将一次网络请求的所有信息serviceMethod对象传递给了OkHttpCall,意思是这次网络请求准备交给OkHttp处理。
final class OkHttpCall<T> implements Call<T> { private final ServiceMethod<T> serviceMethod; private final Object[] args; private volatile boolean canceled; // All guarded by this. private okhttp3.Call rawCall; private Throwable creationFailure; // Either a RuntimeException or IOException. private boolean executed; OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) { this.serviceMethod = serviceMethod; this.args = args; }
内部可以看到,OkHttpCall拥有一个网络请求serviceMethod
return serviceMethod.callAdapter.adapt(okHttpCall); List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories); adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); final class DefaultCallAdapterFactory extends CallAdapter.Factory { static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory(); @Override public CallAdapter<?> 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 call; } }; } }
这行代码会将okHttpCall返回出去。也就是我们自定义接口,方法的返回值:
@GET("v2/fm/app_channels") Call<AppChannels> getAppCannels();
我们请求网络的时候是这样的:
Call<AppChannels> call = AppChannelsClient.get().getAppCannels(); call.enqueue(new MyCallBack<AppChannels>() { @Override public void onSuccess(AppChannels data) { Log.i(TAG, "size:" + data.getGroups().size() + " " + data.toString()); mTextView.setText(data.toString()); } @Override public void onFailure(Call<AppChannels> call, Throwable t) { } });
在OkHttpCall里也有enqueue方法:
@Override public void enqueue(final Callback<T> callback) { if (callback == null) throw new NullPointerException("callback == null"); okhttp3.Call call; Throwable failure; ...
方法里找到:
call = rawCall = 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; } 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(); } }
可以看到,Retrofit里面的确是通过OkHttpClient进行网络请求的。
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
这个callFactory就行Retrofit外面设置的OkHttpClient对象,只是以接口的方式显示,数据跟踪可以知道。
总的来说,当我们以调用接口实现类的方法:
Call<AppChannels> call = AppChannelsClient.get().getAppCannels();
Retrofit会通过动态代理,获取到接口对象,method字段,再通过反射获取到method字段中的注解,请求参数,
将信息存储到serviceMethod中,一个serviceMethod就包含了一次完整请求网络所需要的数据,
Host,Uri,请求参数,请求类型都有,再通过OkHttp的方式去请求网络,获取到json,
在通过Gson转化工厂将json转化成Java Bean,回调的方式传递出去
这就是Retrofit请求网络的源码分析。
注解 + 反射 + 动态代理 ,依赖OkHttp库。
Retrofit源码分析就到这里。
2016年7月06日 02:35:16
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories