Retrifit简单的梳理
Posted 清浅岁月
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Retrifit简单的梳理相关的知识,希望对你有一定的参考价值。
Retrofit
Retrofit的 一次网络请求流程,以及API接口中的参数是如何获取的
内部使用的OkHttp,先把OkHttp的使用放上,在Retrofit的源码中我们知道什么地方开始调用了OkHttpClient了。
OkHttp的使用
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.url("www.baidu.com")
.build();
okHttpClient.newCall(request).enqueue(new okhttp3.Callback()
@Override
public void onFailure(okhttp3.Call call, IOException e)
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException
);
下面是Retrofit的具体使用:
定义的接口APi:
@GET("wor/word")
Call<Data> getData(@Header("apikey")String apikey,
@Query("num")String num,
@Query("page")String page);
具体的请求方法,这里用的是最简单的,没有配置其他的,基本都是默认的:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("")
.addConverterFactory(GsonConverterFactory.create())
.build();
// 通过动态代理的方式创建请求对象
AccountApi accountApi = retrofit.create(AccountApi.class);
Call<Data> dataCall = accountApi.getData("xxx", "xxx", "xxx");
// 异步加载
dataCall.enqueue(new Callback<Data>()
@Override
public void onResponse(Call<Data> call, Response<Data> response)
Data data = response.body();
@Override
public void onFailure(Call<Data> call, Throwable t)
);
这些配置的数据不重要,只看看整个流程,每一步是怎么走的:
先看一下Retrofit build做了哪些配置处理,除了我们配的的哪些参数。
public Retrofit build()
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)
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.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
// 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);
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
需要注意三个地方:
第一个地方是这里, callFactory我们没有配置必然是null,默认直接new的OkHttpClient,OkHttpClient实现了Call.Factory这个接口,所以OkHttpClient就是一个callFactory。
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null)
callFactory = new OkHttpClient();
第二个地方是这里,
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
这里用到了platform,
Builder(Platform platform)
this.platform = platform;
public Builder()
this(Platform.get());
Builder(Retrofit retrofit)
platform = Platform.get();
callFactory = retrofit.callFactory;
baseUrl = retrofit.baseUrl;
converterFactories.addAll(retrofit.converterFactories);
// Remove the default BuiltInConverters instance added by build().
converterFactories.remove(0);
callAdapterFactories.addAll(retrofit.callAdapterFactories);
// Remove the default, platform-aware call adapter added by build().
callAdapterFactories.remove(callAdapterFactories.size() - 1);
callbackExecutor = retrofit.callbackExecutor;
validateEagerly = retrofit.validateEagerly;
Platform返回的是:
private static final Platform PLATFORM = findPlatform();
static Platform get()
return PLATFORM;
private static Platform findPlatform()
try
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0)
return new Android();
catch (ClassNotFoundException ignored)
try
Class.forName("java.util.Optional");
return new Java8();
catch (ClassNotFoundException ignored)
return new Platform();
...
static class Android extends Platform
@Override public Executor defaultCallbackExecutor()
return new MainThreadExecutor();
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor)
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
static class MainThreadExecutor implements Executor
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r)
handler.post(r);
Platform最后返回的就是anroid,在platform.defaultCallAdapterFactory就是这个里面的defaultCallAdapterFactory方法。Retrifit看到这里就可以了。
第三个地方是这里,添加了一个默认的allAdapterFactory对象callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
具体看一下是哪一个CallAdapter对象:
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor)
if (callbackExecutor != null)
return new ExecutorCallAdapterFactory(callbackExecutor);
return DefaultCallAdapterFactory.INSTANCE;
DefaultCallAdapterFactory类很简单没做什么,注意一下adapt这个方法返回的传进来的参数。
*/
final class DefaultCallAdapterFactory extends CallAdapter.Factory
static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit)
if (getRawType(returnType) != Call.class)
return null;
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>()
@Override public Type responseType()
return responseType;
@Override public Call<Object> adapt(Call<Object> call)
return call;
;
接下来看:
AccountApi accountApi = retrofit.create(AccountApi.class);
Call<Data> dataCall = accountApi.getData("", "", "");
retrofit.create的create做什么了,动态代理创建了我们定义的访问接口AccountApi。
public <T> T create(final Class<T> service)
Utils.validateServiceInterface(service);
if (validateEagerly)
eagerlyValidateMethods(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, @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);
if (platform.isDefaultMethod(method))
return platform.invokeDefaultMethod(method, service, proxy, args);
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
);
看最后,
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
loadServiceMethod的入参是动态代理产生的method,看一下是如何获取ServiceMethod的
ServiceMethod<?, ?> loadServiceMethod(Method method)
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache)
result = serviceMethodCache.get(method);
if (result == null)
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
return result;
是从缓存中获取,没有就build,入参是retirfit,和动态代理生成的method,接着上面的获取完loadServiceMethod之后new了一个OkHttpCall
通过刚才获取的serviceMethod的adapt方法,入参是刚才new的okHttpCall,返回一个Call,看一个返回的Call是那一个。
T adapt(Call<R> call)
return callAdapter.adapt(call);
里面调用的是CallAdapter的adapt方法返回的,此时的callAdapter是哪一个的对象,ServiceMethod的build的时候生成的。
public ServiceMethod build()
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class)
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
....
看一下createCallAdapter()是如何创建的,
private CallAdapter<T, R> createCallAdapter()
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType))
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
if (returnType == void.class)
throw methodError("Service methods cannot return void.");
Annotation[] annotations = method.getAnnotations();
try
//noinspection unchecked
return (CallAdapter<T, R>) 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);
最后返回的是retrofit.callAdapter的callAdapter,retifit对象是在serviceMethod的build的时候穿进来的,所以之前retrofit发热build的时候注意的第三点在这个时候就用的到了,回头看,callAdapter是DefaultCallAdapterFactory。
找到callAdapter,接着上面的流程,调用callAdapter的adapt方法,返回的还是OkHttpCall,绕了半天返回的就是OkHttpCall自己。
拿到Call,调用Call的enquene执行异步请求。看一下这个OkHttpCAll是怎么请求网络的。
@Override public void enqueue(final Callback<T> callback)
checkNotNull(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)
callFailure(e);
return;
try
callback.onResponse(OkHttpCall.this, response);
catch (Throwable t)
t.printStackTrace();
@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)
t.printStackTrace();
);
注意这里
if (call == null && failure == null)
try
call = rawCall = createRawCall();
catch (Throwable t)
throwIfFatal(t);
failure = creationFailure = t;
在OkHttpCall里面的enquene并没有真正的去获取数据,call为空调用createRawCall();创一个call再去获取,接着看这个reateRawCall()做什么了:
private okhttp3.Call createRawCall() throws IOException
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null)
throw new NullPointerException("Call.Factory returned null.");
return call;
调的是serviceMethod之前在newPkHttpCall的时候传递进来的对象的toCall方法,
/** Builds an HTTP request from method arguments. */
okhttp3.Call toCall(@Nullable Object... args) throws IOException
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length)
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
for (int p = 0; p < argumentCount; p++)
handlers[p].apply(requestBuilder, args[p]);
return callFactory.newCall(requestBuilder.build());
该方法最后调的callFactory的newCall方法,还记得在retrofit的build的第一个注意的地方吗?CallFactory是谁,是默认new的OkhttpClient对不对?没错就是它,最终调的是OkhttpClient的newCall,此时retrifit的工作已经完成了,将接力棒交给okHttpClient进行网络访问。
看一下,OkHttpClient的的newCall是如何操作的:
@Override public Call newCall(Request request)
return RealCall.newRealCall(this, request, false /* for web socket */);
再看RealCall.newRealCall是怎么实现的:
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket)
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
真正的网络请求是RealCall的enquene发起的:
@Override public void enqueue(Callback responseCallback)
synchronized (this)
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
AsyncCall是一个内部类:、
final class AsyncCall extends NamedRunnable
private final Callback responseCallback;
AsyncCall(Callback responseCallback)
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
String host()
return originalRequest.url().host();
Request request()
return originalRequest;
RealCall get()
return RealCall.this;
@Override protected void execute()
boolean signalledCallback = false;
try
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled())
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
else
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
catch (IOException e)
if (signalledCallback)
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
else
eventListener.callFailed(RealCall.this, e);
responseCallback.onFailure(RealCall.this, e);
finally
client.dispatcher().finished(this);
真正的请求响应来自于getResponseWithInterceptorChain();这个方法:
Response getResponseWithInterceptorChain() throws IOException
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket)
interceptors.addAll(client.networkInterceptors());
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
到此其实还没有网络请求,纳尼,涉及到OKHttp的拦截器,list中添加各种拦截器,简单看一下拦截器的定义
public interface Interceptor
Response intercept(Chain chain) throws IOException;
interface Chain
Request request();
Response proceed(Request request) throws IOException;
/**
* Returns the connection the request will be executed on. This is only available in the chains
* of network interceptors; for application interceptors this is always null.
*/
@Nullable Connection connection();
Call call();
int connectTimeoutMillis();
Chain withConnectTimeout(int timeout, TimeUnit unit);
int readTimeoutMillis();
Chain withReadTimeout(int timeout, TimeUnit unit);
int writeTimeoutMillis();
Chain withWriteTimeout(int timeout, TimeUnit unit);
很简单接口里面又定义了一个接口Chain,这个chain就是链子。
将之前准备好的数据都给RealInterceptorChain这个类,并且执行它proceed方法。
看一下最后一个创建连接的
这个里面会不断的链式调用的,还是看一下ConnectInterceptor,在这里才回去发起连接请求服务器:
public final class ConnectInterceptor implements Interceptor
public final OkHttpClient client;
public ConnectInterceptor(OkHttpClient client)
this.client = client;
@Override public Response intercept(Chain chain) throws IOException
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Request request = realChain.request();
StreamAllocation streamAllocation = realChain.streamAllocation();
// We need the network to satisfy this request. Possibly for validating a conditional GET.
boolean doExtensiveHealthChecks = !request.method().equals("GET");
HttpCodec httpCodec = streamAllocation.newStream(client, chain, doExtensiveHealthChecks);
RealConnection connection = streamAllocation.connection();
return realChain.proceed(request, streamAllocation, httpCodec, connection);
大致的流程图:
看一下RealConnection,这里面调用的Okio进行的网络请求,详情请到这里。录标题)
欢迎使用Markdown编辑器
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
新的改变
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- 全新的界面设计 ,将会带来全新的写作体验;
- 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
- 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
- 全新的 KaTeX数学公式 语法;
- 增加了支持甘特图的mermaid语法1 功能;
- 增加了 多屏幕编辑 Markdown文章功能;
- 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
- 增加了 检查列表 功能。
功能快捷键
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
合理的创建标题,有助于目录的生成
直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC
语法后生成一个完美的目录。
如何改变文本的样式
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
插入链接与图片
链接: link.
图片:
带尺寸的图片:
居中的图片:
居中并且带尺寸的图片:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
如何插入一段漂亮的代码片
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片
.
// An highlighted block
var foo = 'bar';
生成一个适合你的列表
- 项目
- 项目
- 项目
- 项目
- 项目1
- 项目2
- 项目3
- 计划任务
- 完成任务
创建一个表格
一个简单的表格是这么创建的:
项目 | Value |
---|---|
电脑 | $1600 |
手机 | $12 |
导管 | $1 |
设定内容居中、居左、居右
使用:---------:
居中
使用:----------
居左
使用----------:
居右
第一列 | 第二列 | 第三列 |
---|---|---|
第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
SmartyPants
SmartyPants将ASCII标点字符转换为“智能”印刷标点html实体。例如:
TYPE | ASCII | HTML |
---|---|---|
Single backticks | 'Isn't this fun?' | ‘Isn’t this fun?’ |
Quotes | "Isn't this fun?" | “Isn’t this fun?” |
Dashes | -- is en-dash, --- is em-dash | – is en-dash, — is em-dash |
创建一个自定义列表
-
Markdown
- Text-to- HTML conversion tool Authors
- John
- Luke
如何创建一个注脚
一个具有注脚的文本。2
注释也是必不可少的
Markdown将文本转换为 HTML。
KaTeX数学公式
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \\Gamma(n) = (n-1)!\\quad\\forall n\\in\\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分
Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \\Gamma(z) = \\int_0^\\infty t^z-1e^-tdt\\,. Γ(z)=∫0∞tz−1e−tdt.
你可以找到更多关于的信息 LaTeX 数学表达式here.
新的甘特图功能,丰富你的文章
- 关于 甘特图 语法,参考 这儿,
UML 图表
可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::
这将产生一个流程图。:
- 关于 Mermaid 语法,参考 这儿,
FLowchart流程图
我们依旧会支持flowchart的流程图:
- 关于 Flowchart流程图 语法,参考 这儿.
导出与导入
导出
如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。
导入
如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。
注脚的解释 ↩︎
以上是关于Retrifit简单的梳理的主要内容,如果未能解决你的问题,请参考以下文章