OkHttp+Retrofit使用分析
目前Android的网络请求最流行的应该就是OkHttp + Retrofit,在平时开发的项目中也用到了这一套框架,现在对源码的一些实现进行分析。Retrofit2.0最新版本默认集成OkHttp3.3,此源码分析也基于此版本。
1.网络层架构介绍
01.png 图源:Piasy由上图可以看到,Android客户端使用这套框架进行网络请求,基本层次结构分为:Okio进行流操作,处理与服务端的传输信息;OkHttp作为网络请求客户端对请求与响应进行了一层封装;Retrofit在此进行的操作是对每个请求与响应创建的格式化操作,处理请求以及转化接收的响应数据,可以添加不同的Converter进行不同数据结构的转化。
Android系统提供了两种HTTP通信类,HttpURLConnection和HttpClient。由于HttpClient的API太多,难以对它们进行改进容易破坏兼容性,所以Android官方停止了对它的维护以及集成。OkHttp是一个相对成熟的解决方案,据说Android4.4的源码中可以看到HttpURLConnection已经替换成了OkHttp实现。
Android官方对两种请求方式的选择建议
2.使用分析
2.1初始化
2.1.1创建Retrofit、OkHttpClient对象
//创建Retrofit
Retrofit retrofit = new Retrofit.Builder()
.client(OKHttpFactory.INSTANCE.getOkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
//创建OkHttpClient
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder
//打印日志拦截器
.addInterceptor(new HttpLogInterceptor())
//下载进度拦截器
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse
.newBuilder()
.body(new FileResponseBody(originalResponse))
.build();
}
});
okHttpClient = builder.build();
此项目中OkHttpClient创建方式使用的传统builder,官方也提供了一个快捷的创建方式,此方式使用了默认的一些设置:
OkHttpClient client = new OkHttpClient();
//构造方法
public OkHttpClient() {
this(new Builder());
}
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
}
如果没有特殊需求可以使用这种方式创建OkHttpClient对象
2.1.2定义API获取实例
interface GoogleService {
/**
* 谷歌框架请求接口
* @param param
* @return
*/
@FormUrlEncoded
@POST("api/google/getGoogleApks")
Observable<HttpResult<List<AppInfoBean>>> getGoogleFrameApks(
@Field("param")JSONObject param);
/**
* 下载apk
* @param fileUrl
* @return
*/
@GET
Call<ResponseBody> downloadFile(@Url String fileUrl);
}
GoogleService googleService = retrofit.create(GoogleService.class);
现在看Retrofit.create()方法的实现
public <T> T create(final Class<T> service) {
...
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, Object... args)
throws Throwable {
...
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
这里使用的是动态代理技术,动态生成接口的实现类,并创建代理类,代理把对接口的调用转发给InvocationHandler,这样的好处就是所有对接口方法的调用都会在InvocationHandler的invoke方法实现中进行处理,在此方法中可以进行自定义的数据统计等操作。
2.1.3 调用API方法
Call<ResponseBody> downloadCall = googleService.downloadFile(apkUrl);
//外部传入回调接口实例
downloadCall.enqueue(callback);
由于Retrofit支持RxJava,将返回值类型设置为Observable,可以更方便对数据进行处理。
示例代码如下:
Observable<List<ArticleData>> observable = googleService.getArticles(jsonObject);
observable
.observeOn(Schedulers.io())
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(new ProgressSubscriber<List<ArticleData>>() {
@Override
public void onError(Throwable e) {
...
}
@Override
public void onNext(List<ArticleData> o) {
...
}
});
2.2 API执行代码解析
Retrofit请求解析流程图
[图片上传失败...(image-e9d981-1519442347531)]
在Retrofit初始化的creat方法中,以下三行代码执行真正的请求操作:
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
2.2.1 ServiceMethod< T >
loadServiceMethod(method) 的方法实现:
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
由此看到每个ServiceMethod对象对应API接口的一个方法,在获取的时候serviceMethodCache实现了缓存,同一个API的同一个方法只会创建一次。
ServiceMethod构造函数的实现:
ServiceMethod(Builder<T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod;
this.relativeUrl = builder.relativeUrl;
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
-
callFactory
负责创建HTTP请求,返回的是Okhttp3.Call类对象,如Call类说明文档:
A call is a request that has been prepared for execution.
A call can be canceled.
As this object represents a single request/response pair (stream), it cannot be executed twice.
一个准备好执行的请求。请求可以取消,由于代表一个单一的请求/响应流,所以不能被执行两次。
builder.retrofit.callFactory();
此处callFactory()在Retrofit的build()方法中可以看到默认返回一个OkHttpClient对象;
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
初始化Retrofit的时候也可以指定其他的callFactory创建HTTP请求,此处Retrofit默认必须使用OkHttpClient,如需使用其他客户端要修改源码重新编译。
-
callAdapter
private CallAdapter<?> createCallAdapter() { ... Annotation[] annotations = method.getAnnotations(); try { return retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(e, "Unable to create call adapter for %s", returnType); } }
callAdapter也在Retrofit中进行创建,Retrofit类内部遍历adapterFactories列表,工厂提供需要的callAdapter,如果没有工厂能够提供将抛出异常,Retrofit初始化时可以添加不同的工厂,此项目中用到的是RxJavaCallAdapterFactory,使用此工厂API方法即可以返回Observable对象。
-
responseConverter
private Converter<ResponseBody, T> createResponseConverter() { Annotation[] annotations = method.getAnnotations(); try { return retrofit.responseBodyConverter(responseType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(e, "Unable to create converter for %s", responseType); } }
responseConverter的创建和上面两个对象一样也是在Retrofit中创建,由Retrofit初始化时进行添加,主要负责的是进行请求响应的自动化解析工作,此项目中用到的是GsonConverterFactory解析json数据.
Retrofit初始化时converterFactories会默认添加一个BuiltInConverters转换器,该转换器继承自Converter.Factory,Converter.Factory正是对每个HTTP请求参数转换为字符串,
其中提供了requestBodyConverter和stringConverter,@Body 和 @Part 类型的参数使用 requestBodyConverter 进行转换,其他类型的参数使用stringConverter转换。
-
parameterHandlers
private ParameterHandler<?> parseParameter( int p, Type parameterType, Annotation[] annotations) { ParameterHandler<?> result = null; for (Annotation annotation : annotations) { ParameterHandler<?> annotationAction = parseParameterAnnotation( p, parameterType, annotations, annotation); } ... return result; }
parameterHandlers由ServiceMethod的parseParameter创建,API接口方法的每个参数都会生成一个parameterHandler,它负责解析参数使用的注解类型(比如上面用到的@ Field,@Url等).
创建Retrofit实例时,用户根据自己的需求创建不同的工厂,让Retrofit不同模块之间高度解耦,代码更加清晰。
2.2.2 OkHttpCall
OkHttpCall实现了retrofit.Call接口,平时使用到execute()和enqueue(Callback<T> callback)这两个接口,前者是同步执行HTTP请求,后者为异步执行,真正的请求在okhttp3的RealCall类中进行,由以下代码可以看出enqueue()执行的异步请求。
void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
...
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
...
return call;
}
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) {
...
}
if (code == 204 || code == 205) {
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
...
}
}
由execute的源码可以看到执行HTTP请求包括三步:
- 1 创建okhttp3.Call:createRawCall(),此处用到的callFactory默认为OkHttpClient;
- 2 执行网络请求:call.execute();
- 3 解析请求结果数据:parseResponse(call.execute());
2.2.3 CallAdapter
serviceMethod.callAdapter.adapt(okHttpCall);
CallAdapter<T>#adapt(Call<R> call) 函数负责把 retrofit2.Call<R> 转为 T,此项目中使用的是RxJavaCallAdapterFactory,返回类型T也就是RxJavaCallAdapterFactory创建的CallAdapter行为;
RxJavaCallAdapterFactory的get 方法中对返回值的类型进行了检查,只支持 rx.Single,rx.Completable 和 rx.Observable,一般使用RxJava返回值类型都是Obeservable,主要看一下对Obeservable的支持。
private CallAdapter<Observable<?>> getCallAdapter(Type returnType, Scheduler scheduler) {
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
if (rawObservableType == Response.class) {
...
Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
return new ResponseCallAdapter(responseType, scheduler);
}
if (rawObservableType == Result.class) {
...
Type responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
return new ResultCallAdapter(responseType, scheduler);
}
return new SimpleCallAdapter(observableType, scheduler);
}
这里进一步对返回值的泛型类型进行检查;除了retrofit2.Response和retrofit2.adapter.rxjava.Result类型外,都返回的是SimpleCallAdapter,使用SimpleCallAdapter进行数据转换。
public <R> Observable<R> adapt(Call<R> call) {
Observable<R> observable = Observable.create(new CallOnSubscribe<>(call))
.lift(OperatorMapResponseToBodyOrError.<R>instance());
if (scheduler != null) {
return observable.subscribeOn(scheduler);
}
return observable;
}
创建一个Observable对象,使用lift操作符将retrofit2.Response转换为OperatorMapResponseToBodyOrError.<R>instance()我们声明的返回结果类型或者错误类型;
OperatorMapResponseToBodyOrError进行的操作如下:
public Subscriber<? super Response<T>> call(final Subscriber<? super T> child) {
return new Subscriber<Response<T>>(child) {
@Override public void onNext(Response<T> response) {
if (response.isSuccessful()) {
child.onNext(response.body());
} else {
child.onError(new HttpException(response));
}
}
@Override public void onCompleted() {
child.onCompleted();
}
@Override public void onError(Throwable e) {
child.onError(e);
}
};
}
请求成功之后就将请求结果数据向后传递,response.body()就是我们定义的泛型类型。