关键类功能说明
Retrofit
Retrofit提供的子系统
- serviceMethodCache(自定义的接口映射对象集合) 2. baseUrl(请求地址)
- callFactory(默认为OKHttpCall)
- converterFactories(数据解析器工厂集合)
- callAdapterFactories(Call适配器工厂集合)
- callbackExecutor(回调执行,Android平台默认为MainThreadExecutor)
使用Builder模型构建(把对象依赖的零件创建、零件的组装封装起来;以使客户很方便的获取一个复杂
对象;)
Platform
Retrofit中用来管理多平台的方法,支持Android、Java8。通过findPlatform获取对应的平台,同时也 初始化了defaultCallAdapterFactory工厂
ServiceMethod
接口映射的网络请求对象,通过动态代理,将自定义接口的标注转换为该对象,将标注及参数生成 OkHttp所需的Request对象。Retrofit的create通过动态代理拦截,将每一个自定义接口转换成为一个 ServiceMethod对象,并通过通过serviceMethodCache进行缓存
Call
Retrofit定义的网络请求接口,包含execute、enqueue等方法
OkHttpCall
Ohttp的Call实现,通过createRawCall得到真正的 okhttp3.Call对象,用于进行实际的网络请求
CallAdapter.Factory
CallAdapter的静态工厂,包含get的抽象方法,用于生产CallAdapter对象
ExecutorCallAdapterFactory
Android平台默认的CallAdapter工厂,get方法使用匿名内部类实现CallAdapter,返回 ExecutorCallbackCall,实现了Call
ExecutorCallbackCall
采用静态代理设计,delegate实际为OkHttpCall,使用callbackExecutor实现回调在主线程中执行
RxJavaCallAdapterFactory
Rxjava平台的CallAdapter工厂,get方法返回RxJavaCallAdapter对象
RxJavaCallAdapter
Rxjava平台的适配器,返回observable对象
Converter.Factory
数据解析器工厂,用于生产Converter实例
GsonConverterFactory
数据解析工厂实例,返回了GsonResponseBodyConverter数据解析器
GsonResponseBodyConverter
Gson的数据解析器,将服务端返回的json对象转换成对应的java模型
Response
Retrofit网络请求响应的Response
关键的几个流程
Retrofit 如何将定义的interface转换成网络请求?
通过动态代理在ServiceMethod里面转换的Retrofit的Converter机制是如何实现?
Retrofit的CallAdapter机制是如何实现?
通过debug单步调试我们能得出这个 流程图
Retrofit:Call
Response<T> execute() throws IOException;
void enqueue(Callback<T> callback);
创建retrofit对象的时候 创建了一个OkHttpClient 其实是OKHttp里面Call.Factory
OkHttp: Call 真正执行网络请求
这个Call对象 并不是创建Retrofit对象的时候创建
Converter种类
Retrofit支持多种数据解析方式,使用时需要在Gradle添加依赖。
数据解析器 | Gradle依赖 |
---|---|
Gson | com.squareup.retrofit2:converter-gson:version |
Jackson | com.squareup.retrofit2:converter-jackson:version |
Simple XML | com.squareup.retrofit2:converter-simplexml:version |
Protobuf | com.squareup.retrofit2:converter-protobuf:version |
Moshi | com.squareup.retrofit2:converter-moshi:version |
Wire | com.squareup.retrofit2:converter-wire:version |
Scalars | com.squareup.retrofit2:converter-scalars:version |
CallAdapter种类
网络请求适配器 | Gradle依赖 |
---|---|
guava | com.squareup.retrofit2:adapter-guava:version |
Java8 | com.squareup.retrofit2:adapter-java8:version |
rxjava | com.squareup.retrofit2:adapter-rxjava:version |
如何自定义一个Converter及CallAdapter?
CallAdapter
package top.zcwfeng.retrofitdemo.retrofit.calladapter
import androidx.lifecycle.LiveData
import retrofit2.*
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.util.concurrent.atomic.AtomicBoolean
class LiveDataCallAdapterFactory: CallAdapter.Factory(){
companion object{
@JvmStatic
fun create() = LiveDataCallAdapterFactory()
}
override fun get(
returnType: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): CallAdapter<*, *>? {
val responseType: Type
if(getRawType(returnType) != LiveData::class.java){
throw IllegalStateException("return type must be parameterized")
}
val observableType = getParameterUpperBound(0,returnType as ParameterizedType)
val rawObservableType = getRawType(observableType)
responseType = if(rawObservableType == Response::class.java){
if(observableType !is ParameterizedType){
throw java.lang.IllegalStateException("Response must be parameterized")
}
getParameterUpperBound(0,observableType)
}else{ observableType}
return LiveDataCallAdapter<Any>(responseType)
}
}
private class LiveDataCallAdapter<R>(private val responseType: Type): CallAdapter<R, LiveData<R>> {
override fun adapt(call: Call<R>): LiveData<R> {
return object : LiveData<R>(){
private val startedFlag = AtomicBoolean(false)
override fun onActive() {
super.onActive()
if(startedFlag.compareAndSet(false,true)){
call.enqueue(object: Callback<R> {
override fun onFailure(call: Call<R>, t: Throwable) {
postValue(null)
}
override fun onResponse(call: Call<R>, response: Response<R>) {
postValue(response.body())
}
})
}
}
}
}
override fun responseType(): Type = responseType
}
Converter
package top.zcwfeng.retrofitdemo.retrofit.converter
import android.util.JsonToken
import com.google.gson.Gson
import com.google.gson.JsonIOException
import com.google.gson.TypeAdapter
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import okhttp3.MediaType
import okhttp3.RequestBody
import okhttp3.ResponseBody
import okio.Buffer
import retrofit2.Converter
import retrofit2.Retrofit
import java.io.IOException
import java.io.OutputStreamWriter
import java.io.Writer
import java.lang.reflect.Type
import java.nio.charset.Charset
class MyGsonConvertFactory(private val gson:Gson): Converter.Factory() {
companion object{
fun create() = MyGsonConvertFactory(Gson())
fun create(gson:Gson?):MyGsonConvertFactory{
if(gson == null){
throw NullPointerException("gson == null")
}
return MyGsonConvertFactory(gson)
}
}
override fun requestBodyConverter(
type: Type,
parameterAnnotations: Array<Annotation>,
methodAnnotations: Array<Annotation>,
retrofit: Retrofit
): Converter<*, RequestBody>? {
val adapter = gson.getAdapter(TypeToken.get(type))
return null
}
override fun responseBodyConverter(
type: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, *>? {
val adaptation = gson.getAdapter(TypeToken.get(type))
return null
}
private class MyGsonResponsesBodyConvert<T>(
private val gson:Gson,
private val adapter:TypeAdapter<T>
):Converter<ResponseBody,T>{
override fun convert(value: ResponseBody): T? {
val jsonReader:JsonReader = gson.newJsonReader(value.charStream())
return try {
val result = adapter.read(jsonReader)
if(jsonReader.peek() != JsonToken.END_DOCUMENT){
throw JsonIOException("JSON document was not fully consumed.")
}
result
}finally {
value.close()
}
}
}
private class MyGsonRequestBodyConverter<T>(
private val gson: Gson,
private val adapter: TypeAdapter<T>
) :
Converter<T, RequestBody> {
@Throws(IOException::class)
override fun convert(value: T): RequestBody {
val buffer = Buffer()
val writer: Writer =
OutputStreamWriter(buffer.outputStream(), UTF_8)
val jsonWriter: JsonWriter = gson.newJsonWriter(writer)
adapter.write(jsonWriter, value)
jsonWriter.close()
return RequestBody.create(
MEDIA_TYPE,
buffer.readByteString()
)
}
companion object {
private val MEDIA_TYPE: MediaType = MediaType.get("application/json; charset=UTF-8")
private val UTF_8: Charset = Charset.forName("UTF-8")
}
}
}
Java 版本的String Convert
static class ToStringConverterFactory extends Converter.Factory {
private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain");
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
if (String.class.equals(type)) {
return new Converter<ResponseBody, String>() {
@Override
public String convert(ResponseBody value) throws IOException {
return value.string();
}
};
}
return null;
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
if (String.class.equals(type)) {
return new Converter<String, RequestBody>() {
@Override
public RequestBody convert(String value) throws IOException {
return RequestBody.create(MEDIA_TYPE, value);
}
};
}
return null;
}
}
Retrofit中的设计模式
建造者模式
Retrofit对象的创建、ServiceMethod对象创建都使用Build模式,将复杂对象的创建和表示分离,调用 者不需要知道复杂的创建过程,使用Build的相关方法进行配置创建对象。外观模式
Retrofit对外提供了统一的调度,屏蔽了内部的实现,使得使用该网络库简单便捷。
门面模式: 提供一个统一的接口去访问多个子系统的多个不同的接口,它为子系统中的一组接口提供一 个统一的高层接口。使用子系统更容易使用
动态代理模式 通过动态代理的方式,当调用Retrofit的create()方法时,会进行动态代理监听。当执行具体的接口方法
时,会回调InvocationHandler。通过反射解析method的标注及参数,生成ServiceMethod对象。静态代理模式 Android平台默认的适配器ExecutorCallbackCall,采用静态代理的模式。具体的实现delegate为 OkHttpCall。
工厂模式 Converter及CallAdapter的创建都采用了工厂模式进行创建。
适配器模式 CallAdapter的adapt采用了适配器模式,使得interface的返回对象可以动态扩展,增强了灵活性
题外话
所谓:OkHttp 请求速度快 针对连接池进行了复用,用 Okio 优化 socket链接
是对和HttpConnection HttpClient socket链接 角度进行的描述
Volley 和Retrofit是对 网络请求的封装解耦