一、前言
? Retrofit 是基于OkHttp 封装的一个框架,使其更加方便使用。目前也是使用较多的网络框架,这里对其原理进行简单记录。这里需要注意的是Retrofit 框架只是对OkHttp 的二次封装,实际的网络请求依然还是用OkHttp 进行的。因为OkHttp 的网络请求只处理网络请求,对于实际开发中涉及的其余逻辑并不关心,比如线程切换,数据解析等等。另外使用Retrofit 还可以对api的接口进行良好的管理,因此在此基础上研发了Retrofit 框架。
二、简单使用
? 这里简单记录一个使用例子,更多的例子可以查看官方文档和demo。
添加依赖
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
使用方式:
interface ServerApi {
@POST("s?cl=3&tn=baidutop10&fr=top1000&wd=战火中的中国驻乌克兰大使馆&rsv_idx=2&rsv_dl=fyb_n_homepage&sa=fyb_n_homepage&hisfilter=1")
@FormUrlEncoded
fun login(@Field("id") userId: String): Call<String>
@GET("s?cl=3&tn=baidutop10&fr=top1000&wd=战火中的中国驻乌克兰大使馆&rsv_idx=2&rsv_dl=fyb_n_homepage&sa=fyb_n_homepage&hisfilter=1")
fun loginObserver(): Observable<String>
}
class MainActivity : AppCompatActivity() {
private val httpUrl = "http://www.baidu.com"
private fun startRetrofitNet(){
val retrofit = Retrofit.Builder()
.baseUrl(httpUrl)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build()
val serverApi = retrofit.create(ServerApi::class.java)
val loginCall = serverApi.login("123")
loginCall.enqueue(object : Callback<String>{
override fun onResponse(call: Call<String>, response: Response<String>) {
val result = response.body()
Log.e("YM--->","获取的网络内容:${result}")
Toast.makeText(this@MainActivity,"--->",Toast.LENGTH_SHORT).show()
}
override fun onFailure(call: Call<String>, t: Throwable) {
}
})
}
}
三、整体结构
? 从上文的使用方式可以看到,Retrofit 的使用方式和OkHttp 有很多不同的地方:
- 网络请求采用RESTful风格和注解的方式进行配置。这种类似于配置文件式的写法使网络请求更好的维护
- 在进行网络请求中不像
OkHttp 那样涉及到其他部分,比如Request 。这里都可以使用Retrofit 创建的对象进行链式调用进行请求。这是一种基于装饰模式的写法(跟建造者模式不是一回事,区别在于一个是根据多个参数不一样进行动态配置)。 - 在创建过程中可以通过配置
ConverterFactory 进行数据转换。因为有时候传入的数据格式不支持,比如传入一个对象,这时候可以使用转换器转换成字符串,或者将一个字符串在返回的时候转换为一个对象。 - 在创建对象的时候通过配置
CallAdapterFactory 对OkHttp 的Call 对象进行适配。在OkHttp 中Call 是用来对Request 和Response 进行处理的。这里可以看上述接口定义了两个不同的返回值,一个是Call<String> ,另外一个是RxJava的Observable<String> 。使用RxJava的话就可以调用不同的特性,这里就是使用CallAdapterFactory 进行转换的。也可以转换成kotlin这些使用方式。Retrofit 通过重新处理Call 将返回值根据实现的不同的CallAdapterFactory 做不同的转换,提高了强大的拓展性。 - 可以看到上文的响应值里面直接输出了
Toast 。要知道请求是子线程的,Toast 显示是在主线程的,所以这里自己做了线程切换。也是一个很大的不同点。这个线程切换是在Retrofit 默认的DefaultCallAdapterFactory 中做的,其它适配器里面没写的话是没有线程切换的。 - 还有一个重要的不同点从使用上看的话不好直接看出来,那就是定义接口的实例对象都被缓存起来了,防止多次调用同一个对象都去创建新的接口对象,其它的对象也有类似的操作。这里减少了部分内存占用,提高了部分内存性能(因为这个缓存是定义在
Retrofit 类里面的,所以实例对象不一样的话等于没有缓存。)。
上面就是跟OkHttp 的一些区别,那么对于Retrofit 来说,主要有以下几部分组成:
Retrofit ConverterFactory CallAdapterFactory Call<T> - 定义的网络请求接口类
对于他们的主要功能上文已经解释过了,这里就不再进行解释,下面从最基本的网络请求来记录Retrofit 的运行流程。
四、运行流程
? 使用Retrofit 的时候首先要通过建造者模式创建一个实例对象,最终实例对象还是调用的Retrofit 的构造函数,所以这里看下构造函数即可知道有哪些参数:
Retrofit(
okhttp3.Call.Factory callFactory,
HttpUrl baseUrl,
List<Converter.Factory> converterFactories,
List<CallAdapter.Factory> callAdapterFactories,
@Nullable Executor callbackExecutor,
boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = converterFactories;
this.callAdapterFactories = callAdapterFactories;
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
这里简单说下这几个参数的含义:
callFactory : 这个是okhttp 的一个接口,OkHttpClient 就是实现了这个接口,所以可以传入自定义的OkHttpClient baseUrl :故名思义,就是一个网络请求的基础域名converterFactories :数据转换器集合callAdapterFactories : 适配器集合callbackExecutor : 一个用来调度返回值的回调的线程池,默认是主线程validateEagerly : 这个用的不多,源码的意思是检查配置是否有效。通过源码知道定义的接口类是通过动态代理实现具体类的,但是里面的接口需要在调用的时候才进行检查,而这个参数的配置会提前进行检查,即不通过动态代理就可以执行。
当创建完Retrofit 的实例化对象后,需要通过Retrofit::create(final Class<T> service) 来创建接口的实例化对象。这里看下这个对象是如何创建的。
public final class Retrofit {
...
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
...
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);
}
});
}
...
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<?> loadServiceMethod(Method method) 函数。然后可以看到通过ServiceMethod.parseAnnotations(this, method); 得到结果,然后添加进缓存里面去。这里看下这个写法:
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
这里拿到相关方法后进行解析注解然后得到相对应的实体,然后在动态代理里面调用loadServiceMethod(method).invoke(args); 的invoke(args) 函数就是这里面的函数。看下具体实现。
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
...
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
...
}
通过这里就知道在具体实现的适配器里面将数据返回,这个数据结构类型由具体的适配器进行构造。默认的就返回默认的Call 对象,RxJava就返回Observer<T> 对象
五、参考链接
- Retrofit
- 设计模式-代理模式:
- OkHttp原理
- restful接口和普通接口有啥区别_RESTful接口
- Retrofit 2.0中的validateEagerly()方法(beta 2)
|