简单介绍

Retrofit是一套RESTful架构的Android(Java)客户端实现,基于注解,提供JSON to POJO(Plain Ordinary Java Object,简单Java对象),POJO to JSON,网络请求(POST,GET,PUT,DELETE等)封装。

软件首页http://square.github.io/retrofit/

github地址https://github.com/square/retrofit

具体使用

官方文档非常清晰,Retrofit2对Retrofit做了很大改进,针对改进做一下分析和使用说明

底层okhttp不同

Retrofit 默认使用okhttp
Retrofit2 默认使用okhttp3

Service接口定义方式不同

在Retrofit2之前如果定义一个同步的函数,应该这样定义:
public interface GitHubService {      @POST("/list")    Repo loadRepo();  }
异步函数定义
public interface GitHubService {      @POST("/list")    void loadRepo(Callback<Repo> cb);  }
Retrofit2 同步异步方法定义一个接口就可以了
mport retrofit.Call;public interface GitHubService {      @POST("/list")    Call<Repo> loadRepo();  }

如果要调用同步请求,只需调用execute;而发起一个异步请求则是调用enqueue。

Retrofit2 可以取消请求方法

Retrofit2请求使用Call,Call有cancel方法可以取消请求
只需调用call.cancel()就可以取消请求。

Converter现在从Retrofit2中删除,需要根据自己的需要引入Converter

这里是Square提供的官方Converter modules列表。选择一个最满足你需求的。
Gson: com.squareup.retrofit:converter-gsonJackson: com.squareup.retrofit:converter-jacksonMoshi: com.squareup.retrofit:converter-moshiProtobuf: com.squareup.retrofit:converter-protobufWire: com.squareup.retrofit:converter-wireSimple XML: com.squareup.retrofit:converter-simplexml

Retrofit2 新的URL定义方式

Retrofit接口请求URL要求用/开头,必须设置baseUrl,接口请求URL不能是完整路径。可以使用Endpoint切换服务器路径
于 Retrofit2中新的URL定义方式,建议
- Base URL: 总是以 /结尾
- @Url: 不要以 / 开头
Retrofit2中没有Endpoint这个类,@Url中可以包含完整的路径,包含完整路径baseUrl会被忽略
public interface APIService {    @POST("http://api.test.com/test)    Call<Users> loadUsers();}

Retrofit2 需要OkHttp的支持

OkHttp在Retrofit里是可选的。如果你想让Retrofit 使用OkHttp 作为HTTP 连接接口,需要手动包含okhttp 依赖。
但是在Retrofit2中,OkHttp 是必须的,并且自动设置为了依赖。
Retrofit2缺少INTERNET权限会导致SecurityException异常
在Retrofit 中,如果忘记在AndroidManifest.xml文件中添加INTERNET权限。异步请求会直接进入failure回调方法,得到PERMISSION DENIED 错误消息。没有任何异常被抛出。但是在Retrofit2中,当调用call.enqueue或者call.execute,将立即抛出SecurityException,如果不使用try-catch会导致崩溃。

即使response存在问题onResponse依然被调用

在Retrofit中,如果获取的 response 不能背解析成定义好的对象,则会调用failure。但是在Retrofit2中,不管 response 是否能被解析。onResponse总是会被调用。但是在结果不能被解析的情况下,response.body()会返回null。只有抛出异常才会调用onFailure

拦截器不同

在Retrofit中,可以使用RequestInterceptor来拦截一个请求,但是它已经从Retrofit2 移除了,因为HTTP连接层已经完全转为OkHttp。
Retrofit2使用okhttp的拦截器


源码分析

Retrofit的创建

Retrofit是个final类,不能再定义子类,Retrofit没有public构造方法,只能使用构建的者方式Retrofit.Builder构建。 etrofit.Builder可以指定url根地址、采用的网络客户端、回调线程池、请求拦截器、返回数据格式器和错误处理。
通常必须调用baseUrl,addConverterFactory这两个方法。 构建器默认使用OkHttpClient作为网络请求工具,addCallAdapterFactory用来构建请求实例,callbackExecutor指定回调方法线程池,根据不同平台构建不同,Android构建的是defaultCallbackExecutor,默认在主线程中。validateEagerly默认为false,表示执行的时候再去解析注解。如果设置为true,那么create实例之后,就会先解析接口所有方法。

if (baseUrl == null) {       throw new IllegalStateException("Base URL required.");     }<pre name="code" class="java"> public <T> T create(final Class<T> service) {    Utils.validateServiceInterface(service);    if (validateEagerly) {      eagerlyValidateMethods(service);    }    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },......

  

请求实例的创建

调用Retrofit的create方法,创建了执行请求对象的代理,代理方法的执行中,对于Object方法和默认方法,直接执行,其它方法解析后执行。使用代理加注解,是Retrofit的核心思想。
  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 {            // 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 serviceMethod = loadServiceMethod(method);            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);            return serviceMethod.callAdapter.adapt(okHttpCall);          }        });

接口的解析过程

loadServiceMethod中首先从缓存中找解析的方法,找到直接返回,否则解析方法,然后放入缓存中。解析过的接口保存在了serviceMethodCache中,防止重复解析,提高效率。解析方法使用ServiceMethod.Builder构建解析器。 build过程中,首先创建callAdapter, 解析中有一系列规则,发现异常会抛出异常 方法返回的参数不能是泛型,不能是基本数据类型,不能是void。 注解不能为空 创建完callAdapter继续构建其他ServiceMethod属性,需要注意其他抛出异常的情况 返回类型不能是一个Response httpMethod注解不能为空 如果请求中没有body,不能使用Multipart和FormEncoded
参数类型不能是基本类型和泛型
参数不能没有注解
URL不能为空
Form-encoded方法至少包含一个@Field注解
Multipart方法至少包含一个@Part注解
满足以上要求,才能正确构建ServiceMethod。
  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;  }

  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?");      }      responseConverter = createResponseConverter();......

网络请求处理

方法解析完成之后,调用CallAdapter的adapt方法返回Call 内部构建如下
public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {    if (getRawType(returnType) != Call.class) {      return null;    }    final Type responseType = Utils.getCallResponseType(returnType);    return new CallAdapter<Call<?>>() {      @Override public Type responseType() {        return responseType;      }      @Override public <R> Call<R> adapt(Call<R> call) {        return new ExecutorCallbackCall<>(callbackExecutor, call);      }    };  }
此时并没有发起请求,只是构建除了call,具体来说构建的是ExecutorCallbackCall,真正用来执行请求的是call内部的代理delegate,这个代理的真实身份是OkHttpCall,Retrofit2相当于将请求全权交给OKhttp处理,异步请求enqueue方法,同步请求execute方法都是执行的Okhttpclient对应的方法, 一下是okhttp请求的真实创建方法
  private okhttp3.Call createRawCall() throws IOException {    Request request = serviceMethod.toRequest(args);    okhttp3.Call call = serviceMethod.callFactory.newCall(request);    if (call == null) {      throw new NullPointerException("Call.Factory returned null.");    }    return call;  }
异步执行完之后,利用callbackExecutor将回调抛回主线程。
Retrofit2比Retrofit简化了很多,但是功能却更加强大了。真的非常奇妙。作为网络请求框架,整个代码中居然没有用线程池,因为Okhttp本身对异步处理已经做的很好了。充分发挥了其它模块的功能,简化了自身逻辑。


欢迎扫描二维码,关注公众号





更多相关文章

  1. 跨平台移动开发_Android(安卓)平台使用 PhoneGap 方法
  2. Android开发笔记: Project "XXX" is missing required source fo
  3. android 解决依赖冲突
  4. 我的android——OpenGL(2)——gl10方法解析
  5. android EditText里面嵌入两个按钮,通过按钮可以加减EditText里的
  6. android GBK转UTF-8出现乱码问题解决方法
  7. 解决升级 Android(安卓)Studio 3.6.1 后无法运行 Java 代码的问
  8. Android(安卓)project 的常用编译方法
  9. android修改虚拟内存(方法)

随机推荐

  1. 【DB宝19】在Docker中使用MySQL高可用之M
  2. 【DB宝40】MySQL高可用管理工具Orchestra
  3. 【微信小程序】swiper轮播图
  4. 【uni-app/微信小程序】预览图片(单张、多
  5. 【js知识】splice()实现数组的添加、删除
  6. 【微信小程序】tab选项卡
  7. 【js知识】DOM获取元素的方法
  8. 20210202-1 大数据云计算介绍和基础(上)
  9. 【jQuery效果】文字滚动
  10. 20210220-1 Linux命令(上)