Android Retrofit原理深入探索

目录
  • 序章
  • Retrofit构建过程
  • 创建网络请求接口实例过程
  • 执行请求过程
  • 总结

序章

首先引入依赖

implementation 'com.squareup.retrofit2:retrofit:2.9.0'

在原理之前,我们先来回忆一下Retrofit的基本使用

1、定义接口

interface MyService {
    @GET("gallery/{imageType}/response")
    fun getImages(@Path("imageType") imageType: String): Call<List<String>>
}

2、构建Retrofit,创建网络请求接口类实例

        val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .build()
        val myService = retrofit.create(MyService::class.java)

3、生成Call,执行请求

        val resp = myService.getImages("banner")
        resp.enqueue(object : Callback<List<String>> {
            override fun onResponse(call: Call<List<String>>, response: Response<List<String>>) {
                TODO("Not yet implemented")
            }
            override fun onFailure(call: Call<List<String>>, t: Throwable) {
                TODO("Not yet implemented")
            }
        })

这样一个基本的网络请求就搞定了,使用很简洁,正是因为其内部使用了大量的设计模式和优秀的架构设计,才得以使其如此方便地进行网络请求,下面我们就一起来探索探索Retrofit的设计之美。

Retrofit构建过程

使用了建造者模式通过内部静态类Builder构建一个Retrofit实例,这里只列出了部分方法,其他类似

public static final class Builder {
    private final Platform platform;
    // 网络请求工厂,工厂方法模式
    private @Nullable okhttp3.Call.Factory callFactory;
    // 网络请求地址
    private @Nullable HttpUrl baseUrl;
    // 数据转换器工厂的集合
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    // 网络请求适配器工厂的集合,默认是ExecutorCallAdapterFactory
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    // 回调方法执行器,用于切换线程
    private @Nullable Executor callbackExecutor;
    // 一个开关,为true则会缓存创建的ServiceMethod
    private boolean validateEagerly;
    //......
    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();
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
    }
    // 将一个含有Gson对象实例的GsonConverterFactory放入数据转换器工厂
    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
    }
    //......
}

通过build,我们上面Builder类中的参数对象都配置到了Retrofit对象中。

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

创建网络请求接口实例过程

使用动态代理的方式拿到所有注解配置后,创建网络请求接口实例。

  public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T)
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {service},
            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);
              }
            });
  }

跟踪 loadServiceMethod,parseAnnotations解析注解配置得到ServiceMethod,然后加入到serviceMethodCache缓存中,是一个ConcurrentHashMap。

  ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(
          method,
          "Method return type must not include a type variable or wildcard: %s",
          returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }
  abstract @Nullable T invoke(Object[] args);
}

执行请求过程

  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 {
          // 创建一个OkHttp的Request对象请求
          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
            }
          }
        });
  }
  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 {
      // 将响应体转为Java对象
      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;
    }
  }

总结

首先,使用建造者模式通过Builder构建一个Retrofit实例,Builder类中的参数对象都配置到Retrofit对象中,然后使用动态代理的方式拿到所有注解配置后,创建网络请求接口实例,生成OkHttp请求,通过callAdapterFactory找到对应的执行器,比如RxJava2CallAdapterFactory,最后通过ConverterFactory将返回数据解析成JavaBean,使用者只需关心请求参数,内部实现由Retrofit封装完成,底层请求还是基于okhttp实现的。

到此这篇关于Android Retrofit原理深入探索的文章就介绍到这了,更多相关Android Retrofit内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android开发Retrofit源码分析

    目录 项目结构 retrofit 使用 Retrofit #create ServiceMethod #parseAnnotations HttpServiceMethod#parseAnnotations 第二种 非Kotlin协程情况 DefaultCallAdapterFactory#get 第一种 Kotlin协程情况 总结 项目结构 把源码 clone 下来 , 可以看到 retrofit 整体结构如下 图 http包目录下就是一些http协议常用接口 , 比如 请求方法 url ,

  • Android Retrofit框架的使用

    Retrofit介绍 Retrofit是Square开源的一款基于OkHttp(也是他家的)封装的网络请求框架,主要的网络请求还是OkHttp来完成,Retrofit只是对OkHttp进行了封装,可以让我们更加简单方便的使用,目前大部分公司都在使用这款框架,Retrofit的原理也是面试必问的问题之一了,所以我们不仅要会使用,也要对其实现原理有一个大概的了解. 本片文章从使用角度来说,不对的地方希望大家在评论区交流,我会及时改进,共同进步,文章中的demo可以从github下载. Retrofi

  • Android Retrofit的使用详解

    关于Retrofit的学习,我算是比较晚的了,而现在Retrofit已经是Android非常流行的网络请求框架了.之前,我没有学过Retrofit,但最近公司的新项目使用了Retrofit.Rxjava和OkHttp来进行封装,使用起来非常简便,增加代码的美观程度,也降低了耦合度,这是一个非常棒的框架,特别是这三者一起使用. 简介 Retrofit是Square公司开发的一款针对Android网络请求的框架,现在已经更新到2.3版本了.Retrofit的最大特点是使用运行时注解的方式提供功能.

  • Android中Retrofit的简要介绍

    Retrofit A type-safe HTTP client for Android and Java 适用于Java和Android的安全的HTTP客户端 Retrofit是一个可用于Android和Java的网络库,使用它可以简化我们的网络操作,提高效率和正确率.它将请求过程和底层代码封装起来只暴露我们业务中的请求和返回数据模型. public interface GitHubService { @GET("users/{user}/repos") Call<List&l

  • Android使用Retrofit上传文件功能

    本文实例为大家分享了Android使用Retrofit上传文件的具体代码,供大家参考,具体内容如下 一.封装RetrofitManager public class RetrofitManager {     private static RetrofitManager retrofitManager;          private Retrofit retrofit;     private RetrofitManager() {}     public static RetrofitMa

  • Android Retrofit原理深入探索

    目录 序章 Retrofit构建过程 创建网络请求接口实例过程 执行请求过程 总结 序章 首先引入依赖 implementation 'com.squareup.retrofit2:retrofit:2.9.0' 在原理之前,我们先来回忆一下Retrofit的基本使用 1.定义接口 interface MyService { @GET("gallery/{imageType}/response") fun getImages(@Path("imageType") i

  • Android图片框架Glide原理深入探索

    目录 with load into 原理总结 缓存 LruCache 首先引入依赖 implementation 'com.github.bumptech.glide:glide:4.12.0'    annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' 下面一行代码,就是Glide最简单的使用方式了 Glide.with(this).load(url).into(imageView) with 首先,我们来看with,其

  • Android drawFunctor 原理及应用详情

    目录 一. 背景 二. drawFunctor 原理介绍 三. 利用 drawFunctor 注入 GL 渲染 Android Functor 定义 Functor 设计 在 View.onDraw () 中调度 functor 四. 实践中遇到的问题 GL 状态保存&恢复 View变换处理 ContextLost 五. 效果 一. 背景 蚂蚁 NativeCanvas 项目 Android 平台中使用了基于 TextureView 环境实现 GL 渲染的技术方案,而 TextureView 需

  • Android Handler 原理分析及实例代码

    Android Handler 原理分析 Handler一个让无数android开发者头疼的东西,希望我今天这边文章能为您彻底根治这个问题 今天就为大家详细剖析下Handler的原理 Handler使用的原因 1.多线程更新Ui会导致UI界面错乱 2.如果加锁会导致性能下降 3.只在主线程去更新UI,轮询处理 Handler使用简介 其实关键方法就2个一个sendMessage,用来接收消息 另一个是handleMessage,用来处理接收到的消息 下面是我参考疯狂android讲义,写的一个子

  • Android Retrofit 中文乱码问题的解决办法

    Android Retrofit 中文乱码问题的解决办法 使用retrofit和rxjava,提交数据时需注意,当数据中有中文时,传到后台,可能会是乱码,需处理: 解决: 1.GET请求改成POST; 2.参数Field改成Query 3.加上@FormUrlEncoded 如下: @FormUrlEncoded @POST("/test/test") Call<Response> register(@Field("name") String name)

  • Android Retrofit 2.0框架上传图片解决方案

    本文为大家分享了 Android Retrofit 2.0框架上传图片解决方案,具体内容如下 1.单张图片的上传 /** * 上传一张图片 * @param description * @param imgs * @return */ @Multipart @POST("/upload") Call<String> uploadImage(@Part("fileName") String description, @Part("file\&qu

  • Android Retrofit和Rxjava的网络请求

    Android  Retrofit和Rxjava的网络请求 去年的时候好多公司就已经使用Rxjava和Retrofit了,最近自自己学习了一下,感觉真的是很好用,让自己的网络请求变得更简单了,而且封装性极强. 首先做一下准备工作,导入需要引用的文件 compile 'com.android.support:appcompat-v7:25.1.0' testCompile 'junit:junit:4.12' compile 'io.reactivex:rxjava:1.1.0' compile

  • Android Retrofit的简单介绍和使用

    Retrofit与okhttp共同出自于Square公司,retrofit就是对okhttp做了一层封装.把网络请求都交给给了Okhttp,我们只需要通过简单的配置就能使用retrofit来进行网络请求了,其主要作者是Android大神JakeWharton. 导包: compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'//Retrofit2所需要的包 compile 'com.squareup.retrofit2:converter-gso

  • Android 断点续传原理以及实现

    Android 断点续传原理以及实现 0.  前言 在Android开发中,断点续传听起来挺容易,在下载一个文件时点击暂停任务暂停,点击开始会继续下载文件.但是真正实现起来知识点还是蛮多的,因此今天有时间实现了一下,并进行记录. 1.  断点续传原理 在本地下载过程中要使用数据库实时存储到底存储到文件的哪个位置了,这样点击开始继续传递时,才能通过HTTP的GET请求中的setRequestProperty()方法可以告诉服务器,数据从哪里开始,到哪里结束.同时在本地的文件写入时,RandomAc

随机推荐