what is retrofit
A type-safe HTTP client for Android and Java
适用于java8 和android平台。使用okio进行网络请求。
how to use retrofit
//first define an interface discribe the url and param
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
public class RetrofitSample {
public void testRetrofit() {
//定义要访问的url路径
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())//使用不同的json解析器, retrofit只对body进行处理。
.build();
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat");
// 请求数据,并且处理response
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Response<List<Repo>> author) {
Log.d()
}
@Override
public void onFailure(Throwable t) {
} });
//the code above will request url: https://api.github.com/users/octocat/repos
// 返回的值封装成为List<Repo>形式的数值。
}
}
更多用法参考:你真的会用retrofit 这里面有更详细的使用介绍。
how does it work
首先,针对retrofit初始化的代码:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
new Retrofit.Build() 会调用Build(Platform.get())方法,根据是否有"android.os.Build" 来判断是否是android平台, 如果是android平台, 则创建一个主线程执行器, 这里我们可以知道,retrofit需要将任务(例如请求数据完毕,将数据返回到主线程)抛到主线程执行,直接调用MainThreadExcutor.excute(new Runnable(){})就可以了
事实上如果希望使用rxjava或者其他的类型,这里可以通过addAdapterFacotry()添加rxjava的adapter
同时还会添加一个默认的adapter, 对于android,默认的adapter就是ExecutorCallAdapterFactory,
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
除了这些信息,其他的信息通过Builder模式设置即可, 在调用Builder.build()的时候会判断使用哪种客户端(默认Okhttpclient), 哪种线程执行器(android 默认就是上面的MainThreadExecutor执行器), body转换器(没有设置内容转换器 则使用内建转换器), 然后生成了一个Retrofit代码。
对于GitHubService service = retrofit.create(GitHubService.class);
进入到create()内部查看,可以看到其主要实现是通过jdk的动态代理对最开始的GithubApiService做拦截处理。
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, @Nullable 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<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
在invoke方法内部, 主要是拦截GithubApiService已经注解的方法, 解析方法对应的参数,结合传递进来的参数,调用loadservicemethod生成一个serviceMethod实例,该实例保存了要发送请求的所有信息,并将serviceMethod以及参数一起传给OkHttpCall 生成一个实例,并包装成一个ExecutorCallAdaptFacoty(android)的实例。
ServiceMethod.Builder.build()方法先
通过serviceMethod.toRequest 可以将一个servicemethod转换成okhttp所需要的Request(),
最后再看调用Call<T>.enque时,发生了什么事情
repos.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Response<List<Repo>> author) {
Log.d()
}
@Override
public void onFailure(Throwable t) {
} });
这里的repos实际是ExecutorCallAdaptFacoty的实例,查看里面的enque方法,实际调用的是OkHttpCall()的enque方法,并监听回调。而OkHttpCall()的方法实际最后调用的是okhttp3.Call的enque和execute()方法。
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
if (type == ResponseBody.class) {
return Utils.isAnnotationPresent(annotations, Streaming.class)
? StreamingResponseBodyConverter.INSTANCE
: BufferingResponseBodyConverter.INSTANCE;
}
if (type == Void.class) {
return VoidResponseBodyConverter.INSTANCE;
}
return null;
}
在okhttp处理完成后, 在将okhttp返回的数据进行处理时,会调用serviceMethod的toRsponse方法, 而responseconvert 的生成又是根据最开始设置retrofit的值来判断的,默认的类型有 StreamingResponseBodyConverter和BufferingResponseConverter, 实际是根据不同的返回值以及注解类型来做特别处理的。
总结
Retrofit实际是对okhttp的一层封装,通过注解的方式描述了一个http请求需要的信息,简化了okhttp的使用,对于返回数据的解析,使用了默认的Converter, 用户也可以使用其他的converter,例如gson convert等,也可以定义自己的converter。
Retrofit的代码主要是设计模式很牛逼,这里贴一张简书用户stay的模式图:
refs:
Retrofit2