Retrofit是一个相当简洁的网络请求框架,其本质上只是对Okhttp的封装,实际上底层还是用Okhttp来执行网络请求。这两天终于比较闲一些,于是又想起了被我束之高阁的前辈的武功秘籍。
Retrofit的使用
参考官方例子,定义接口并使用
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);
}
// Create a very simple REST adapter which points the GitHub API.
Retrofit retrofit =
new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// Create an instance of our GitHub API interface.
GitHub github = retrofit.create(GitHub.class);
// Create a call instance for looking up Retrofit contributors.
Call<List<Contributor>> call = github.contributors("square", "retrofit");
// Fetch and print a list of the contributors to the library.
List<Contributor> contributors = call.execute().body();
源码阅读
首先来到梦的开始retrofit2.Retrofit#create
,可以看到这里是个动态代理,后续的处理交给retrofit2.ServiceMethod#parseAnnotations
。
而后ServiceMethod中解析注解中的信息
继续阅读,果然在requestFactory的Builder中找到了@GET
、@POST
等注解的处理。
继续HttpServiceMethod,暂时不看Kotlin Suspend Function部分,还是比较清晰的:就是处理了下call adapter,让请求的call对象转换到指定的线程工具上,如RxJava。
CallAdapted继承自HttpServiceMethod,而在HttpServiceMethod我们找到了网络请求对象OkhttpCall。
然而OkhttpCall还是发起请求和处理响应的,发起请求还是用的RequestFactory。requestFactory是在上面解析注解时赋值的,很快找到了实际创建Okhttp对象的位置。
然后Response对象的解析
这里用responseConverter将原始的Response的body转换为解析好的Response对象。
啪,没了。
核心问题
如何自定义注解?
读取注解信息,用于请求参数。处理方法参考:retrofit2.RequestFactory.Builder#parseMethodAnnotation
。
如何将方法转化成Request对象?
借助动态代理实现接口定义方法,借助反射读取到方法形参和注解,借助形参类型和注解确定请求参数,最终在retrofit2.RequestFactory#create
构建出实际的OkhttpRequest。
ServiceMethod的作用?
实现Okhttp Call到call adapter的委托。
adapter,converter的设计思路,如果想要实现将okhttp也变成可替换的应该如何设计代码?
Retrofit对象作为context,维护了各种所需参数和构造方法(factory)。在后续实际需要的位置创建出adapter。如可以定义NetlibAdapterFactory,RequestFactory中用到Okhttp的地方替换为由retrofit.netlibAdapterFactory创建。
InvocationHandler与泛型的使用?
object StubHelper {
private const val TAG = "StubHelper"
fun <T> create(service: Class<T>): T {
return Proxy.newProxyInstance(
service.classLoader, arrayOf<Class<*>>(service),
object : InvocationHandler {
private val emptyArgs = arrayOfNulls<Any>(0)
@Throws(Throwable::class)
override fun invoke(proxy: Any, method: Method, args: Array<Any>?): Any? {
Log.d(TAG, method.toGenericString())
return null
}
}) as T
}
}
最后修改于 2022-06-09