探索Android开源框架 - 2. Retrofit使用及源码
2021-09-17 本文已影响0人
今阳说
- Retrofit是目前Android最优秀的网络封装框架,是对OkHttp网络请求库的封装
- App应用程序通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数,之后由OkHttp完成后续的请求操作;服务器数据返回后,OkHttp将原始的结果交给Retrofit,根据用户需求对结果进行解析;
使用
简单使用
添加依赖
- retrofit2内置了OkHttp,所以无需再单独添加OkHttp依赖了
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
创建Retrofit实例
val baseUrl = "https://api.github.com/"
val okHttpClient = OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(90, TimeUnit.SECONDS)
.build()
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.build()
创建返回数据的类
class RepoList {
@SerializedName("items") val items:List<Repo> = emptyList()
}
data class Repo(
@SerializedName("id") val id: Int,
@SerializedName("name") val name: String,
@SerializedName("description") val description: String,
@SerializedName("stargazers_count") val starCount: String,
)
创建网络请求接口
interface ApiService {
@GET("search/repositories?sort=stars&q=Android")
fun searRepos(@Query("page") page: Int, @Query("per_page") perPage: Int): Call<RepoList>
}
创建网络请求接口实例
val apiService = retrofit.create(ApiService::class.java)
调用接口实例方法获取Call
val call = apiService.searRepos(1, 5)
发送网络请求
1.同步请求
val response: Response<RepoList> = call.execute()
if (response.isSuccessful) {
val repo = response.body()
LjyLogUtil.d(repo.toString())
} else {
LjyLogUtil.d("code=${response.code()}, msg=${response.message()}")
LjyLogUtil.d(IOException("Unexpected code $response").message)
}
2.异步请求
call.enqueue(object : Callback<RepoList> {
override fun onResponse(call: Call<RepoList>, result: Response<RepoList>) {
if (result.body() != null) {
val repoList: RepoList = result.body()!!
for (it in repoList.items) {
LjyLogUtil.d("${it.name}_${it.starCount}")
LjyLogUtil.d(it.description)
}
}
}
override fun onFailure(call: Call<RepoList>, t: Throwable) {
LjyLogUtil.d("onFailure:${t.message}")
}
})
注解类型
1. 网络请求方法
@GET, @POST, @PUT, @DELETE, @HEAD, @PATCH,@OPTIONS
- 分别对应 HTTP中的网络请求方式
- 注解的value属性用来设置相对/完整url, 如果是完整url则可以覆盖创建Retrofit实例时的baseUrl
- Retrofit把网络请求的URL分成了两部分设置,一是创建Retrofit实例时设置的baseUrl,另一半是 网络请求方法注解的value设置或@Url中设置的部分,
@GET("api/items")
fun getRepos(): Call<RepoList>
@GET("https://api.github.com/api/items")
fun getRepos(): Call<RepoList>
@HTTP
- 替换以上注解的作用 及 更多的功能拓展
/**
* method:网络请求的方法(区分大小写)
* path:网络请求地址路径
* hasBody:是否有请求体
*/
@HTTP(method = "GET", hasBody = false)
fun getRepos(@Url url: String): Call<RepoList>
@HTTP(method = "GET", path = "api/items/{userId}", hasBody = false)
fun getRepos2(@Path("userId") userId: String) : Call<RepoList>
2. 标记
@FormUrlEncoded
- 表示请求体(RequestBody)是Form表单
@FormUrlEncoded
@POST("api/search")
fun searchRepo( @Field("name") repoName:String): Call<RepoList>
@Multipart
- 表示请求体是一个支持文件上传的Form表单
- 具体使用见下面的@Part部分
@Streaming
- 表示返回的数据以流的形式返回,适用于返回数据较大的场景(若没有使用该注解,默认是吧数据全部载入内存中)
@Streaming
@GET
fun downloadFile(@Url url: String?): Call<ResponseBody>
3. 网络请求参数
@Path
- URL地址的缺省值
@GET("api/items/{userId}/repos")
fun getItem(@Path("userId") userId: String): Call<Repo>
//在发起请求时, {userId} 会被替换为方法的参数 userId(被@Path注解的参数)
@Url
- 直接传入一个请求的url,和@GET,@POST等注解的value属性设置url类似,但是通过参数传入显然更灵活一点
@FormUrlEncoded
@POST("api/search")
fun searchRepo(@Url url: String, @Field("name") repoName: String): Call<RepoList>
@Header & @Headers
- 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头
- 使用方式:@Header作用于方法的参数;@Headers作用于方法
@Streaming
@GET
fun downloadFile(@Header("RANGE") start:String , @Url url: String?): Call<ResponseBody>
@Headers("Content-Type: application/json;charset=UTF-8")
@POST("api/search")
fun searchRepo2(@Body params: Map<String, Any>): Call<RepoList>
- 添加header还可以通过上一篇介绍过的okHttp拦截器实现
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(object : Interceptor{
override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
val request=chain.request().newBuilder()
.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
.addHeader("Accept-Encoding", "gzip, deflate")
.addHeader("Connection", "keep-alive")
.addHeader("Accept", "*/*")
.addHeader("Cookie", "add cookies here")
.build()
return chain.proceed(request)
}
})
.build()
@Query & @QueryMap
- 用于 @GET 方法的查询参数
@GET("search/repositories?sort=stars&q=Android")
fun searRepos(@Query("page") page: Int, @Query("per_page") perPage: Int): Call<RepoList>
@GET("search/repositories?sort=stars&q=Android")
fun searRepos(@QueryMap params: Map<String, Any>): Call<RepoList>
@Field & @FieldMap
- 发送 Post请求 时提交请求的表单字段,与 @FormUrlEncoded 注解配合使用
@FormUrlEncoded
@POST("api/search")
fun searchRepo(@Url url: String, @Field("name") repoName: String): Call<RepoList>
@FormUrlEncoded
@POST("api/search")
fun searchRepo(@Url url: String, @FieldMap params: Map<String, Any>): Call<RepoList>
@Part & @PartMap
- 发送 Post请求 时提交请求的表单字段, 与 @Multipart 注解配合使用
- 与@Field的区别:功能相同,但携带的参数类型更加丰富,包括数据流,所以适用于 有文件上传 的场景
@POST("upload/imgFile")
@Multipart
fun uploadImgFile(
@Part("userId") userId: RequestBody?,
@PartMap partMap: Map<String, RequestBody?>,
@Part("file") file: MultipartBody.Part
): Call<ResponseBody>
@Multipart
@POST("upload/files")
fun uploadFiles(
@Part("userId") userId: RequestBody?,
@Part files: List<MultipartBody.Part>
): Call<ResponseBody>
//使用:
val userId: RequestBody = RequestBody.create(MediaType.parse("multipart/form-data"), "1111")
val paramsMap: MutableMap<String, RequestBody> = HashMap()
paramsMap["userId"] = RequestBody.create(MediaType.parse("text/plain"), "123456")
paramsMap["userName"] = RequestBody.create(MediaType.parse("text/plain"), "jinYang")
paramsMap["taskName"] = RequestBody.create(MediaType.parse("text/plain"), "新建派单")
val imgFile=File(externalCacheDir, "ljy.jpg")
val requestFile: RequestBody =
RequestBody.create(MediaType.parse("multipart/form-data"),imgFile )
val partFile = MultipartBody.Part.createFormData("imageUrl", imgFile.name, requestFile)
apiService.uploadImgFile(userId,paramsMap,partFile)
val imgFile1=File(externalCacheDir, "ljy1.jpg")
val imgFile2=File(externalCacheDir, "ljy2.jpg")
val imgFile3=File(externalCacheDir, "ljy3.jpg")
val imageFiles= arrayOf(imgFile1,imgFile2,imgFile3)
val parts = ArrayList<MultipartBody.Part>(imageFiles.size)
for (i in imageFiles.indices) {
val file: File = imageFiles[i]
parts[i] = MultipartBody.Part.createFormData(
"file_$i", file.name, RequestBody.create(
MediaType.parse("image/*"), file
)
)
}
apiService.uploadFiles(userId,parts)
@Body
- 以 Post方式 传递 自定义数据类型 给服务器,如果提交的是一个Map,那么作用相当于 @Field
@Headers("Content-Type: application/json;charset=UTF-8")
@POST("api/add")
fun addRepo(@Body repo: Repo): Call<Boolean>
@Headers("Content-Type: application/json;charset=UTF-8")
@POST("api/add")
fun addRepo2(@Body params: Map<String, Any>): Call<Boolean>
@Headers("Content-Type: application/json;charset=UTF-8")
@POST("api/add")
fun addRepo3(@Body body: RequestBody): Call<Boolean>
@FormUrlEncoded
@POST("api/add")
fun addRepo4(@Body body: FormBody): Call<Boolean>
//使用:
val repo = Repo(1, "name", "info", "20")
apiService.addRepo(repo)
val map: MutableMap<String, Any> = HashMap()
map["key"] = "value"
apiService.addRepo2(map)
val body: RequestBody = RequestBody
.create(MediaType.parse("application/json; charset=utf-8"), repo.toString())
apiService.addRepo3(body)
val formBody = FormBody.Builder()
.add("key", "value")
.build()
apiService.addRepo4(formBody)
数据解析器 & 请求适配器
- Retrofit支持多种数据解析方式和网络请求适配器,使用时需要在Gradle添加依赖
数据解析器
- 默认情况下Retrofit只支持将HTTP的响应体转换换为Call<ResponseBody>,有了Converter就可以把ResponseBody替换成其他类型,
如我们常用的GsonConverterFactory,下面列出官方给我们提供的Converter;
1. 添加依赖
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'//Gson的支持 [常用] [可选]
implementation 'com.squareup.retrofit2:converter-simplexml:2.9.0'//simplexml的支持 [可选]
implementation 'com.squareup.retrofit2:converter-jackson:2.9.0'//jackson的支持 [可选]
implementation 'com.squareup.retrofit2:converter-protobuf:2.9.0'//protobuf的支持 [可选]
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'//moshi的支持 [可选]
implementation 'com.squareup.retrofit2:converter-wire:2.9.0'//wire的支持 [可选]
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'//String的支持 [可选]
2. 创建Retrofit实例时添加
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(JacksonConverterFactory.create())
.addConverterFactory(SimpleXmlConverterFactory.create())
.addConverterFactory(ProtoConverterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create())
.build()
3. 自定义Converter
- 自定义之前我们先来看看官方是如何实现的, 以平时最常用的GsonConverterFactory为例
//继承Converter.Factory
public final class GsonConverterFactory extends Converter.Factory {
//静态的create方法
public static GsonConverterFactory create() {
return create(new Gson());
}
public static GsonConverterFactory create(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
return new GsonConverterFactory(gson);
}
private final Gson gson;
private GsonConverterFactory(Gson gson) {
this.gson = gson;
}
//重写responseBodyConverter方法,将响应体交给GsonResponseBodyConverter处理
@Override
public Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
//重写requestBodyConverter方法,将请求体交给GsonRequestBodyConverter处理
@Override
public Converter<?, RequestBody> requestBodyConverter(
Type type,
Annotation[] parameterAnnotations,
Annotation[] methodAnnotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
//处理响应体的Converter,实现Converter<ResponseBody, T>接口
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
//重写convert方法,将ResponseBody通过Gson转为自定义的数据模型类
@Override
public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
T result = adapter.read(jsonReader);
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
return result;
} finally {
value.close();
}
}
}
//处理请求体的Converter,实现Converter<T, RequestBody>接口
final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");
private static final Charset UTF_8 = Charset.forName("UTF-8");
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
//重写convert方法,通过Gson将自定义的数据模型类转换为RequestBody
@Override
public RequestBody convert(T value) throws IOException {
Buffer buffer = new Buffer();
Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
JsonWriter jsonWriter = gson.newJsonWriter(writer);
adapter.write(jsonWriter, value);
jsonWriter.close();
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
}
- 那么我们来自己试试吧:
- 例1:返回格式为Call<String>
//1. 自定义StringConverter,实现Converter
class StringConverter : Converter<ResponseBody, String> {
companion object {
val INSTANCE = StringConverter()
}
@Throws(IOException::class)
override fun convert(value: ResponseBody): String {
return value.string()
}
}
//2. 自定义StringConverterFactory,用来向Retrofit注册StringConverter
class StringConverterFactory : Converter.Factory() {
companion object {
private val INSTANCE = StringConverterFactory()
fun create(): StringConverterFactory {
return INSTANCE
}
}
// 只实现从ResponseBody 到 String 的转换,所以其它方法可不覆盖
override fun responseBodyConverter(
type: Type,
annotations: Array<Annotation?>?,
retrofit: Retrofit?
): Converter<ResponseBody, *>? {
return if (type === String::class.java) {
StringConverter.INSTANCE
} else null
//其它类型不处理,返回null
}
}
3. 使用
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
// 自定义的Converter一定要放在官方提供的Converter前面
//addConverterFactory是有先后顺序的,多个Converter都支持同一种类型,只有第一个才被使用
.addConverterFactory(StringConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build()
- 例2:ResponseBody转换为Map
class MapConverterFactory : Converter.Factory() {
companion object {
fun create(): MapConverterFactory {
return MapConverterFactory()
}
}
override fun responseBodyConverter(
type: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, *> {
return MapConverter()
}
class MapConverter : Converter<ResponseBody, Map<String, String>> {
@Throws(IOException::class)
override fun convert(body: ResponseBody): Map<String, String> {
val map: MutableMap<String, String> = HashMap()
val content = body.string()
val keyValues = content.split("&").toTypedArray()
for (i in keyValues.indices) {
val keyValue = keyValues[i]
val splitIndex = keyValue.indexOf("=")
val key = keyValue.substring(0, splitIndex)
val value = keyValue.substring(splitIndex + 1, keyValue.length)
map[key] = value
}
return map
}
}
}
请求适配器
- Converter是对于Call<T>中T的转换,而CallAdapter则可以对Call转换,下面列出官方给我们提供的CallAdapter;
1. 添加依赖
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'//RxJava支持 [常用] [可选]
implementation 'com.squareup.retrofit2:adapter-java8:2.9.0'//java8支持 [可选]
implementation 'com.squareup.retrofit2:adapter-guava:2.9.0'//guava支持 [可选]
2. 创建Retrofit实例时添加
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addCallAdapterFactory(Java8CallAdapterFactory.create())
.addCallAdapterFactory(GuavaCallAdapterFactory.create())
.build()
3. 自定义CallAdapter
- 同样的我们来看看官方的RxJava2CallAdapterFactory是如何实现的
//适配器工厂类,继承CallAdapter.Factory
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
//静态的create方法
public static RxJava2CallAdapterFactory create() {
return new RxJava2CallAdapterFactory(null, false);
}
...
//Rxjava的调度器scheduler
private final @Nullable Scheduler scheduler;
private final boolean isAsync;
//构造方法
private RxJava2CallAdapterFactory(@Nullable Scheduler scheduler, boolean isAsync) {
this.scheduler = scheduler;
this.isAsync = isAsync;
}
//重写get方法,返回RxJava2CallAdapter
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(returnType);
...
return new RxJava2CallAdapter(
responseType, scheduler, isAsync, isResult, isBody, isFlowable, isSingle, isMaybe, false);
}
}
//适配器类,实现CallAdapter接口
final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {
private final Type responseType;
RxJava2CallAdapter(Type responseType,....){this.responseType = responseType;....}
...
//重写responseType方法
@Override
public Type responseType() {
return responseType;
}
//重写adapt方法,通过 RxJava2 将Call转换为Observable
@Override
public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable =
isAsync ? new CallEnqueueObservable<>(call) : new CallExecuteObservable<>(call);
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return RxJavaPlugins.onAssembly(observable);
}
}
- 然后我们自己试试搞一个
//1. 自定义Call
class LjyCall<T>(private val call: Call<T>) {
@Throws(IOException::class)
fun get(): T? {
return call.execute().body()
}
}
//2. 自定义CallAdapter
class LjyCallAdapter<R>(private val responseType: Type) : CallAdapter<R, Any> {
override fun responseType(): Type {
return responseType
}
override fun adapt(call: Call<R>): Any {
return LjyCall(call)
}
}
//3. 自定义CallAdapterFactory
class LjyCallAdapterFactory : CallAdapter.Factory() {
companion object {
private val INSTANCE = LjyCallAdapterFactory()
fun create(): LjyCallAdapterFactory {
return INSTANCE
}
}
override fun get(
returnType: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): CallAdapter<R, Any>? {
// 获取原始类型
val rawType = getRawType(returnType)
if (rawType == LjyCall::class.java && returnType is ParameterizedType) {
val callReturnType = getParameterUpperBound(0, returnType)
return LjyCallAdapter(callReturnType)
}
return null
}
}
//4. 使用
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
//也是放到前面,有先后顺序
.addCallAdapterFactory(LjyCallAdapterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
源码解析
- 源码地址: square/retrofit
Retrofit & Builder
Builder的构造方法
- Retrofit实例通过Builder(建造者)模式创建, 那么我们来看看Builder的构造方法
public static final class Builder {
//平台类型对象
private final Platform platform;
//网络请求工厂,默认使用OkHttpClient, 生产网络请求器(Call)
private @Nullable okhttp3.Call.Factory callFactory;
//url的基地址,注意这里的类型是HttpUrl,而非String
private @Nullable HttpUrl baseUrl;
//数据转换器工厂集合
private final List<Converter.Factory> converterFactories = new ArrayList<>();
//适配器工厂集合
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
//回调方法执行器,在 Android 上默认是封装了 handler 的 MainThreadExecutor
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
public Builder() {
this(Platform.get());
}
Builder(Platform platform) {
this.platform = platform;
}
...
}
- 可以看到构造函数中platform是通过Platform.get()获取的,那么来看看Platform.get()代码的实现,
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
return "Dalvik".equals(System.getProperty("java.vm.name"))
? new Android() //
: new Platform(true);
}
...
}
- 很明显我们需要的是Android的实现,它的defaultCallbackExecutor返回封装了Handler的MainThreadExecutor,
其作用是可以从工作线程切换到UI线程
static final class Android extends Platform {
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
...
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
Builder.build()
- 生成Retrofit实例最后需要调用build, 那么我们来看看该方法的实现
public Retrofit build() {
//可以看到baseUrl是必须设置的
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//callFactory 默认使用OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//这里就是对应上面Android的defaultCallbackExecutor,返回封装了Handler的MainThreadExecutor,
callbackExecutor = platform.defaultCallbackExecutor();
}
//数据解析器的集合:
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
//适配器的集合:
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
- 上面可以看到baseUrl是必须设置的,那么再来看看其有何要求呢
public Builder baseUrl(String baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
//如果host后面由路径,则必须以’/‘结尾
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
/**
* Returns a list of path segments like {@code ["a", "b", "c"]} for the URL {@code
* http://host/a/b/c}. This list is never empty though it may contain a single empty string.
*
* <p><table summary="">
* <tr><th>URL</th><th>{@code pathSegments()}</th></tr>
* <tr><td>{@code http://host/}</td><td>{@code [""]}</td></tr>
* <tr><td>{@code http://host/a/b/c"}</td><td>{@code ["a", "b", "c"]}</td></tr>
* <tr><td>{@code http://host/a/b%20c/d"}</td><td>{@code ["a", "b c", "d"]}</td></tr>
* </table>
*/
public List<String> pathSegments() {
return pathSegments;
}
- 上面build方法中说了,callFactory 默认使用OkHttpClient,可能从命名上看并不是一个类型,
但是如果我们看看OkHttpClient源码就会发现它实现了Call.Factory;
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
...
}
Retrofit的构造方法
- 看过了Builder再来看看我们的主角Retrofit,先来看看其变量和构造方法
public final class Retrofit {
//网络请求配置对象的集合(对网络请求接口中方法注解进行解析后得到的对象)
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
//下面几个在Builder中都有过介绍了
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;
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; // Copy+unmodifiable at call site.
this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
...
}
Retrofit的create方法
- 使用中我们创建了retrofit实例后,会调用其create方法生成接口的动态代理对象,代码如下
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
//通过动态代理创建接口的实例
Proxy.newProxyInstance(
//参数1:classLoader
service.getClassLoader(),
//参数2:接口类型数组
new Class<?>[] {service},
//参数3:实现了InvocationHandler的代理类
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 the method is a method from Object then defer to normal invocation.
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,并加入到serviceMethodCache中缓存
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
//先在缓存map中获取
result = serviceMethodCache.get(method);
if (result == null) {
//取不到新建一个并加入缓存
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
- 上面代码的解析工作实际是调用 ServiceMethod.parseAnnotations,通过 RequestFactory 完成对注解的解析的
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
...
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
+
abstract @Nullable T invoke(Object[] args);
}
- 那么再来看看RequestFactory.parseAnnotations中干了点啥吧
final class RequestFactory {
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
...
static final class Builder {
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
//获取网络请求方法的注解:如@GET,@POST@HTTP
this.methodAnnotations = method.getAnnotations();
//获取网络请求方法参数的类型
this.parameterTypes = method.getGenericParameterTypes();
//获取网络请求参数的注解,如@Url,@Path,@Query等
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
//build方法
RequestFactory build() {
//解析网络请求方法的注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
//解析网络请求方法参数的类型和注解
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
...
return new RequestFactory(this);
}
//解析网络请求方法的注解,看到下面的是不是很眼熟,有点豁然开朗了
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
//解析网络请求方法参数的类型和注解
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
...
result = annotationAction;
}
}
...
return result;
}
//解析网络请求方法参数的类型和注解
@Nullable
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
//判断参数的注解注解
if (annotation instanceof Url) {
...
gotUrl = true;
//判断参数的类型
if (type == HttpUrl.class
|| type == String.class
|| type == URI.class
|| (type instanceof Class && "android.net.Uri".equals(((Class<?>) type).getName()))) {
return new ParameterHandler.RelativeUrl(method, p);
}
...
} else if (annotation instanceof Path) {
...
gotPath = true;
Path path = (Path) annotation;
String name = path.value();
validatePathName(p, name);
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Path<>(method, p, name, converter, path.encoded());
} else if (annotation instanceof Query) {
...
} else if (annotation instanceof QueryName) {
...
} else if (annotation instanceof QueryMap) {
...
} else if (annotation instanceof Header) {
...
} else if (annotation instanceof HeaderMap) {
...
} else if (annotation instanceof Field) {
...
} else if (annotation instanceof FieldMap) {
...
} else if (annotation instanceof Part) {
...
} else if (annotation instanceof PartMap) {
...
}
return null; // Not a Retrofit annotation.
}
}
...
}
- ServiceMethod.parseAnnotations中最后是调用HttpServiceMethod.parseAnnotations获取ServiceMethod实例的
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
...
//获取方法注解
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
...
} else {
//网络请求方法的返回值类型就是请求适配器的类型
adapterType = method.getGenericReturnType();
}
//请求适配器
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
...
//数据解析器
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
//从retrofit获取请求工厂,默认的话是OkHttpClient
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
...
}
//CallAdapted继承了HttpServiceMethod
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
//adapt方法的实现,调用callAdapter的adapt方法
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
- 到这里我们就知道了Retrofit的create方法中的loadServiceMethod(method).invoke(args),实际是调用的HttpServiceMethod的invoke方法
- 那么我们看一下HttpServiceMethod的invoke方法,其中调用的adapt方法就是上面CallAdapted的adapt,传入的call类型为OkHttpCall;
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
- 从上面代码可以知道Retrofit中的Call实际是用的OkHttpCall
OkHttpCall 的同步请求方法 execute
- 从上面Retrofit的create方法我们知道,下面代码中的call.execute实际是调用了OkHttpCall的execute方法
val apiService = retrofit.create(ApiService::class.java)
val call = apiService.searRepos(1, 5)
val response: Response<RepoList> = call.execute()
if (response.isSuccessful) {
val repo = response.body()
LjyLogUtil.d(repo.toString())
} else {
LjyLogUtil.d(IOException("Unexpected code $response").message)
}
- OkHttpCall.execute代码如下,其中创建的一个okHttp库的Call对象,到这就说明了Retrofit中的网络请求实际是交给okHttp处理的;
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
//创建okhttp3.Call
call = getRawCall();
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
@GuardedBy("this")
private okhttp3.Call getRawCall() throws IOException {
okhttp3.Call call = rawCall;
if (call != null) return call;
...
return rawCall = createRawCall();
...
}
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;
}
- 上面execute中通过getRawCall获取okhttp3.Call,getRawCall中又通过createRawCall中的callFactory.newCall创建okhttp3.Call,newCall的入参是通过requestFactory.create创建的请求对象
OkHttpCall 的异步请求方法 enqueue
- 上面看过了同步请求的过程,异步请求也是一样通过okHttp.Call进行异步请求的
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
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(); // TODO this is not great
}
}
@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(); // TODO this is not great
}
}
});
}
OkHttpCall 的 parseResponse方法
- 通过上面代码我们发现OkHttpCall的同步异步请求都调用了parseResponse方法,其代码如下,
其中通过 T body = responseConverter.convert(catchingBody),用数据解析器对响应体进行解析,
这个responseConverter就是ServiceMethod的build方法调用createResponseConverter方法返回的Converter;
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse =
rawResponse
.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
Retrofit中的设计模式
Builder(建造者)模式
- 将复杂对象的构建和表示相分离,使复杂对象的构建简单化
- 防止构造方法参数过多,造成使用者使用不便,通过链式调用不同方法设置不同参数
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
- 关于建造者模式如需了解更多内容可以查看Android设计模式-2-建造者模式
工厂模式
- 将“类实例化的操作”与“使用对象的操作”分开,降低耦合,易于扩展,有利于产品的一致性
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
// 自定义的Converter一定要放在官方提供的Converter前面
.addConverterFactory(StringConverterFactory.create())
.addConverterFactory(MapConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(LjyCallAdapterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
- 关于工厂模式如需了解更多内容可以查看:
策略模式
— 策略类之间可以自由切换,由于策略类都实现同一个接口,所以使它们之间可以自由切换。
- 易于扩展,增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合“开闭原则“
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addCallAdapterFactory(Java8CallAdapterFactory.create())
.addCallAdapterFactory(GuavaCallAdapterFactory.create())
.build()
- 关于策略模式如需了解更多内容可以查看Android设计模式-6-策略模式
观察者模式
- 定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新
//call为被观察者,Callback为观察者
call.enqueue(object : Callback<RepoList> {
override fun onResponse(call: Call<RepoList>, result: Response<RepoList>) {
if (result.body() != null) {
val repoResult: RepoList = result.body()!!
for (it in repoResult.items) {
LjyLogUtil.d("${it.name}_${it.starCount}")
}
}
}
override fun onFailure(call: Call<RepoList>, t: Throwable) {
LjyLogUtil.d("onFailure:${t.message}")
}
})
- 关于观察者模式如需了解更多内容可以查看Android设计模式-11-观察者模式
适配器模式
- 定义一个包装类,用于包装不兼容接口的对象
- 可以让没有关联的类一起运行,提高了类的复用
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
private final @Nullable Executor callbackExecutor;
DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
...
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
}
}
- 适配器模式在Android中最常见的使用就是listView,recycleView的Adapter
- 关于适配器模式如需了解更多内容可以查看Android设计模式-19-适配器模式
装饰模式
- 动态扩展一个实现类的功能,装饰类和被装饰类可以独立发展,不会相互耦合
//ExecutorCallbackCall是装饰者,而里面真正去执行网络请求的还是OkHttpCall
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on
// cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
}
- 关于装饰模式如需了解更多内容可以查看Android设计模式-20-装饰模式
外观模式
- 为复杂的模块或子系统提供外界访问的接口
- 通过创建一个统一的类,用来包装子系统中一个或多个复杂的类
- Retrofit类就是Retrofit框架提供给我们的外观类
public final class Retrofit {
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;
...
}
- 关于外观模式如需了解更多内容可以查看Android设计模式-22-外观模式
代理模式
- 也称委托模式,间接访问目标对象, 分为静态代理和动态代理
//Retrofit.create
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
//通过动态代理创建接口的实例
Proxy.newProxyInstance(
//参数1:classLoader
service.getClassLoader(),
//参数2:接口类型数组
new Class<?>[] {service},
//参数3:实现了InvocationHandler的代理类
new InvocationHandler() {
...
});
}
- 静态代理
abstract class AbsObject {
abstract fun doSomething()
}
class RealObject : AbsObject() {
override fun doSomething() {
LjyLogUtil.d("RealObject.doSomething")
}
}
class ProxyObject(private val realObject: RealObject) : AbsObject() {
override fun doSomething() {
LjyLogUtil.d("before RealObject")
realObject.doSomething()
LjyLogUtil.d("after RealObject")
}
}
//使用
val realObject = RealObject()
val proxyObject = ProxyObject(realObject)
proxyObject.doSomething()
- 动态代理
interface Subject {
fun doSomething()
}
class Test : Subject {
override fun doSomething() {
LjyLogUtil.d("Test.doSomething")
}
}
class DynamicProxy(private val target: Subject) : InvocationHandler {
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
LjyLogUtil.d("Proxy:${proxy?.javaClass?.name}")
LjyLogUtil.d("before target")
//Kotlin中数组转为可变长参数,通过前面加*符号
val invoke = method!!.invoke(target, *(args ?: emptyArray()))
LjyLogUtil.d("after target")
return invoke
}
}
//使用:
val test = Test()
val myProxy = DynamicProxy(test)
val subject: Subject =
Proxy.newProxyInstance(
test.javaClass.classLoader,
test.javaClass.interfaces,
myProxy
) as Subject
subject.doSomething()
LjyLogUtil.d("subject.className:" + subject.javaClass.name)
- 关于代理模式如需了解更多内容可以查看Android设计模式-17-代理模式
参考文章
- square/retrofit
- Retrofit谷歌官方详解
- 你真的会用Retrofit2吗?Retrofit2完全教程
- Android网络编程(十一)源码解析Retrofit
- Android:手把手带你 深入读懂 Retrofit 2.0 源码
- Android主流三方库源码分析(二、深入理解Retrofit源码)