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编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销: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. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点html实体。例如:

TYPEASCIIHTML
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)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t &ThinSpace; . \\Gamma(z) = \\int_0^\\infty t^z-1e^-tdt\\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接 长方形 圆角长方形 菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.2.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

以上是关于Retrifit简单的梳理的主要内容,如果未能解决你的问题,请参考以下文章

Retrifit2.0

Android.22.Retrifit文件上传和下载

C++ 梳理:跑通简单程序

编辑器用法

markdown 文本 模板

markdown 文本 模板