Retrofit 网络框架源码解析

栏目: IOS · Android · 发布时间: 6年前

内容简介:本文介绍 Retrofit 网络框架,包含简单的使用和源码解析。Type-safe HTTP client for Android and Java by Square, Inc.前面介绍过 OkHttp ,Retrofit 是对 OkHttp 网络请求框架的封装,前者专注于接口的封装,后者专注于真正的网络请求。

本文介绍 Retrofit 网络框架,包含简单的使用和源码解析。 本文内容基于 Retrofit 2.4.0 版本

Type-safe HTTP client for Android and Java by Square, Inc. http://square.github.io/retrofit/

前面介绍过 OkHttp ,Retrofit 是对 OkHttp 网络请求框架的封装,前者专注于接口的封装,后者专注于真正的网络请求。

Retrofit 网络框架源码解析

应用程序通过 Retrofit 请求网络,实际上是由 Retrofit 接口层封装请求参数、Header、Url 等信息,由 OkHttp 完成实际的请求操作;在服务端返回数据后,OkHttp 将原始的结果交给 Retrofit,Retrofit 根据用户的需求对结果进行解析。

Retrofit 的简单使用

参考官网的介绍:

1、创建 HTTP API 接口

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

2、创建 Retrofit 实例,并实现接口实例

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();
GitHubService service = retrofit.create(GitHubService.class);

3、创建请求实例

Call<List<Repo>> call = service.listRepos("wshunli");

4、发送网络请求

// 同步请求
call.execute();
// 异步请求
call.enqueue(new Callback<List<Repo>>() {
    @Override
    public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {

    }
    @Override
    public void onFailure(Call<List<Repo>> call, Throwable t) {
        Log.d(TAG, "onFailure: ");

    }
});

和 OkHttp 流程差不多,特别是发送请求方法名字都没有变。

Retrofit 的源码分析

Retrofit 网络请求完整的流程图如下:

Retrofit 网络框架源码解析

下面详细介绍。

创建 Retrofit 实例

Retrofit 实例化,也是使用的建造者模式。

Retrofit 网络框架源码解析

我们先看 Builder 成员变量的含义:

// Retrofit#Builder
public static final class Builder {
// 当前系统环境
private final Platform platform;
// 网络请求器的工厂
private @Nullable okhttp3.Call.Factory callFactory;
// 网络请求地址
private HttpUrl baseUrl;
// 数据转换器工厂集合
private final List<Converter.Factory> converterFactories = new ArrayList<>();
// 网络请求适配器工厂集合
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
// 回调方法执行器
private @Nullable Executor callbackExecutor;
// 标志位
private boolean validateEagerly;

1、首先构造函数中通过 Platform.get() 初始化了平台参数

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
class 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();
  }

  /* 省略部分无关代码 */

}

后面如果有需要,我们也可以直接拷贝。

2、然后设置 Retrofit 所需的参数即可

public Builder baseUrl(String baseUrl) {
    checkNotNull(baseUrl, "baseUrl == null");
    HttpUrl httpUrl = HttpUrl.parse(baseUrl);
    if (httpUrl == null) {
    throw new IllegalArgumentException("Illegal URL: " + baseUrl);
    }
    return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
    checkNotNull(baseUrl, "baseUrl == null");
    List<String> pathSegments = baseUrl.pathSegments();
    if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
    throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
    }
    this.baseUrl = baseUrl;
    return this;
}

/** Add converter factory for serialization and deserialization of objects. */
public Builder addConverterFactory(Converter.Factory factory) {
    converterFactories.add(checkNotNull(factory, "factory == null"));
    return this;
}

public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
    callAdapterFactories.add(checkNotNull(factory, "factory == null"));
    return this;
}

3、最后是 build() 方法

public Retrofit build() {
    if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
    }

    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);
}

创建 API 实例

获取 API 实例使用 Retrofit 的 create() 方法

// Retrofit#create()
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);
            }
        });
}

创建 API 实例使用的是 动态代理 设计模式。

创建请求实例

创建请求实例,跟钱买你的动态代理有关。

// Retrofit#create()
ServiceMethod<Object, Object> serviceMethod =
    (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);

1、 loadServiceMethod() 方法

一个 ServiceMethod 对应于一个 API 接口的一个方法, loadServiceMethod() 方法负责加载 ServiceMethod

// Retrofit#loadServiceMethod()
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;
}

2、 OkHttpCall

OkHttpCall 实现了 retrofit2.Call ,我们通常会使用它的 execute()enqueue() 接口。

OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
}

构造方法也没有什么好看的。

发送网络请求

发送网络请求其实也就是 OkHttpCall 类中的方法。

1、 同步请求 使用 execute() 方法

// OkHttpCall#execute()
@Override public Response<T> execute() throws IOException {
    okhttp3.Call call;

    synchronized (this) {
        if (executed) throw new IllegalStateException("Already executed.");
        executed = true;

        if (creationFailure != null) {
            if (creationFailure instanceof IOException) {
                throw (IOException) creationFailure;
            } else if (creationFailure instanceof RuntimeException) {
                throw (RuntimeException) creationFailure;
            } else {
                throw (Error) creationFailure;
            }
        }

        call = rawCall;
        if (call == null) {
            try {
                call = rawCall = createRawCall();
            } catch (IOException | RuntimeException | Error e) {
                throwIfFatal(e); //  Do not assign a fatal error to creationFailure.
                creationFailure = e;
                throw e;
            }
        }
    }

    if (canceled) {
        call.cancel();
    }

    return parseResponse(call.execute());
}

这里就是 Retrofit 和 OkHttp 交互的核心了,分为三步:

(1)创建 okhttp3.Call ,包括构造参数

private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = serviceMethod.toCall(args);
    if (call == null) {
        throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
}

(2)执行网络请求,也就是 OkHttp 的同步网络请求

call.execute()

(3)解析返回的结果

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);
    }

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
        T body = serviceMethod.toResponse(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;
    }
}

2、 异步请求 使用 enqueue() 方法

@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();
        }
        }
    });
}

我们可以看到和同步请求是一致的,实际请求交给了 okhttp3.Call#enqueue(Callback responseCallback) 来实现,并在它的 callback 中调用 parseResponse() 解析响应数据,并转发给传入的 callback

Retrofit 源码就先介绍到这里了,后面有机会再详细介绍。

参考资料

1、Retrofit分析-漂亮的解耦套路 - 简书

https://www.jianshu.com/p/45cb536be2f4

2、Android:手把手带你 深入读懂 Retrofit 2.0 源码 - 简书

https://www.jianshu.com/p/0c055ad46b6c

3、Retrofit源码分析(超详细) - 简书

https://www.jianshu.com/p/097947afddaf

4、拆轮子系列:拆 Retrofit - Piasy的博客 | Piasy Blog

https://blog.piasy.com/2016/06/25/Understand-Retrofit/

5、Retrofit源码解析 | mundane的幻想空间

https://mundane799699.github.io/2018/03/13/retrofit-analysis/

6、Retrofit源码解析 - 掘金

https://juejin.im/post/5acee62c6fb9a028df22ffee

7、Retrofit源码解析 | 俞其荣的博客 | Qirong Yu’s Blog

https://yuqirong.me/2017/08/03/Retrofit源码解析/

8、android-cn/android-open-project-analysis

https://github.com/android-cn/android-open-project-analysis/tree/master/tool-lib/network/retrofit

9、【Android】Retrofit源码分析 - CSDN博客

https://blog.csdn.net/u010983881/article/details/79933220

如果本文对您有所帮助,且您手头还很宽裕,欢迎打赏赞助我,以支付网站服务器和域名费用。 Retrofit 网络框架源码解析 您的鼓励与支持是我更新的最大动力,我会铭记于心,倾于博客。

本文链接: https://www.wshunli.com/posts/2bda06ba.html


以上所述就是小编给大家介绍的《Retrofit 网络框架源码解析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Boolean Reasoning

Boolean Reasoning

Brown, Frank Markham / 2003-4 / $ 19.15

A systematic treatment of Boolean reasoning, this concise, newly revised edition combines the works of early logicians with recent investigations, including previously unpublished research results. Th......一起来看看 《Boolean Reasoning》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具