前言:Retrofit是基于OkHttp封装的一个网络请求框架,既然是OkHttp的上层框架,当然是解决了OkHttp在开发中的一些痛点。具体的来说:
使用过程中接口配置繁琐,OkHttp中每发起一个请求都要新建一个Request,当要配置复杂请求(body,请求头,参数)时尤其复杂。
需要用户拿到responseBody后自己手动解析,解析工作应该是可以封装的。
无法适配自动进行线程切换。
嵌套网络请求会陷入“回调陷阱”
Retrofit基本使用 依赖:
1 2 3 implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:adapter-rxjava:2.9.0'
构建接口Service:
1 2 3 4 public interface ApiService { @GET("users/{users}") Call<UserBean> getUserData (@Path("users") String users) ; }
使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 static Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://gitee.com/api/v5/" ) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); final ApiService service = retrofit.create(ApiService.class);final Call<UserBean> result = service.getUserData("caoyangim" );result.enqueue(new Callback<UserBean>() { public void onResponse (Call<UserBean> call, Response<UserBean> response) { if (response.isSuccessful()){ System.out.println("success:" +response.body()); } } public void onFailure (Call<UserBean> call, Throwable throwable) { System.out.println("ERROR:" +throwable.toString()); } });
注解
get
post
put
delete
patch
head
options
http 通用注解,可以替换以上所有注解,其拥有method,path,hasbody三个属性
源码解析 构建Retrofit网络实例对象 在创建retrofit网络实例对象的时候用到了build建造者模式【一般 配置参数大于5个 & 参数可选 就要用build模式了】,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 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(); } List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this .callAdapterFactories); callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor)); List<Converter.Factory> converterFactories = new ArrayList<>( 1 + this .converterFactories.size() + platform.defaultConverterFactoriesSize()); ... return new Retrofit( callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); } }
TIP:Retrofit在这里提供了一个统一的入口,所有需要的东西都通过build模式往里面加就行了,用的时候也是用retrofit.create()用,所以这里也用到了“外观(门面)模式”
retrofit.create() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public <T> T create (final Class<T> service) { validateServiceInterface(service); return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] {service}, new InvocationHandler() { private final Platform platform = Platform.get(); private final Object[] emptyArgs = new Object[0 ]; @Override public @Nullable Object invoke (Object proxy, Method method, @Nullable Object[] args) throws Throwable { if (method.getDeclaringClass() == Object.class) { return method.invoke(this , args); } args = args != null ? args : emptyArgs; return platform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args); } }); }
这里面用到了动态代理 的技术,你传入一个带有获取数据方法的接口,这个方法帮你动态的生成一个代理类继承该接口,这样一来所有的获取数据的方法都走这里的invoke函数,就可以拦截调用函数的执行,从而将网络接口的参数配置归一化。
即你每次发起网络请求看似是走的自己定义的接口,实际上它是会走到这个方法中来的。
然后往下一般会走loadServiceMethod(method)方法,此方法的作用是解析传入的这个方法,主要是通过解析它的注解获取请求路径、传递参数等属性,返回的是一个ServiceMethod对象。
loadServiceMethod 1 2 3 4 5 6 7 8 9 10 11 12 13 ServiceMethod<?> loadServiceMethod(Method method) { ServiceMethod<?> result = serviceMethodCache.get(method); if (result != null ) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null ) { result = ServiceMethod.parseAnnotations(this , method); serviceMethodCache.put(method, result); } } return result; }
从这个方法可以看出有个缓存 机制,解决了每次都使用反射带来的效率问题。
ServiceMethod/HttpServiceMethod
里面还有几个属性:
1 2 3 4 5 6 abstract class HttpServiceMethod <ResponseT , ReturnT > extends ServiceMethod <ReturnT > { ... private final RequestFactory requestFactory; private final okhttp3.Call.Factory callFactory; private final Converter<ResponseBody, ResponseT> responseConverter; }
retrofit构建了所有的网络请求共同的一些属性,而serviceMethod对应着某个单独的网络请求,其内部属性更加具体化。
请求数据-getUserData 因为用到了动态代理模式,所有不管你接口中写了什么自定义的请求方法,他都会被转到动态代理的类中来:即上面说到的loadServiceMethod():
1 2 3 return platform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args);
loadServiceMethod中会走到parseAnnotations中,返回了一个ServiceMethod对象:
1 2 3 4 5 @Override final @Nullable ReturnT invoke (Object[] args) { Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); }
1 2 3 4 @Override protected ReturnT adapt (Call<ResponseT> call, Object[] args) { return callAdapter.adapt(call); }
返回值的类型根据callAdapter来定,一般可以用defalultCallAdapter,RxJavaCallAdapter 或者也可以自定义callAdapter,只需重写adapt方法即可:收到的是call,根据自己的需求返回即可。
enqueue enqueue最终是调用到了OkHttpCall.enqueue方法中来,在这里面实际上是用到了okhttp的相关方法,比如createRawCall():
1 2 3 4 5 6 7 private okhttp3.Call createRawCall () throws IOException { okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); if (call == null ) { throw new NullPointerException("Call.Factory returned null." ); } return call; }
返回的是okHttp3中的call,然后用这个call:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 call.enqueue( new okhttp3.Callback() { @Override public void onResponse (okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; try { response = parseResponse(rawResponse); } catch (Throwable e) { throwIfFatal(e); callFailure(e); return ; } try { callback.onResponse(OkHttpCall.this , response); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); } } @Override public void onFailure (okhttp3.Call call, IOException e) { callFailure(e); } private void callFailure (Throwable e) { try { callback.onFailure(OkHttpCall.this , e); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); } } });
这些都是okhttp3的用法,被封装到了retrofit中。
再在返回结果的时候用到callbackExecutor.execute来切换了线程,executor实际上是:
1 2 3 4 5 6 7 8 static final class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute (Runnable r) { handler.post(r); } }
设计模式 retrofit中用到了门面(外观)模式,建造者模式,代理模式(动态代理)等设计模式的思想。
retrofit中你可以通过很多组件式的方式使用,比如callAdapter的选择上,可以选择java8的,可以选择RxJava/RxJava2的,scala的方式来编码;获取数据后数据转换方面(convert),可以使用gson ,jackson,moshi甚至xml的方式,都可以自己根据需求选择。这些可以自定义的来组合使用,即外观模式。
建造者模式和代理模式分别在业务代码和源码中可以体现出来。