Retrofit解析JSON API使用总结

直到3个月之前我对Retrofit的认识还停留在”不明觉厉”的层面

实习期间,公司Android项正在将网络请求库从Volley更换至OkHttp + Retrofit
同时了解到后台服务器接口返回的响应数据格式,是一种叫JSON API的JSON数据响应格式

于是便开始针对Retrofit解析JSON API进行探索学习
文章是模拟从0开始学习Retrofit,最终到使用Retrofit解析JSON API的主线


OkHttp + Retrofit的好处

我想先按罗列下我们比较熟悉的Android网络请求框架

  • HttpUrlConnection
    (JDK自带)
  • HttpClient
    (Apache的子项目,Android6.0之前SDK自带,6.0之后需要手动引入才能使用)
  • okhttp
    (出自Android开源大佬Square,一个高效的Http请求框架,具有很强的扩展性)
  • android-async-http
    (底层封装HttpClient,目前已经停止更新)
  • Volley
    (网络请求与图片加载于一身的框架,Volley网络请求底层封装的HttpUrlConnection,在2.3以下使用的是HttpClient,也可以手写代码使其支持OkHttp,大文件传输存在硬伤,目前已经停止更新)
  • retrofit
    (出自Android开源大佬Square,类似上面二位对网络请求进行二次封装,不过相比解耦更彻底具有更强的扩展性)

Volley在大文件传输方面存在硬伤,官方当初发布Volley时的定位便是小而密集的请求这就注定他不能胜任所有网络请求场景


回头看Retrofit,Android网络请求目前最火的框架就是OkHttp + Retrofit了

二者出自同一家公司,Retrofit底层默认使用OkHttp,画风首先就很和谐
OkHttp专注于网络请求数据传输(效率高,功能全面,扩展性强)
Retrofit专注于简化网络请求使整个过程更加优雅便捷(轻松配置url参数,请求适配器;实现反序列化,异步回调等等)

Retrofit作为Square公司Android开源全家桶的重要成员,Square为Retrofit准备了Converter-Gson、Adapter-Rxjava等众多可玩性极高的周边,使其越发强大

二者组合发起网络请求最直观的感受就是方便,减少了代码量
其次就是逻辑清晰,便于阅读

简单配置使用Retrofit发送请求

先简单模拟下使用OkHttp + Retrofit 发送请求的一个流程

  • 引入OkHttp与Retrofit都很简单(看需求添加converters,adapter,mock等相周边关依赖)

    compile 'com.squareup.okhttp3:okhttp:3.X.X'
    compile 'com.squareup.retrofit2:retrofit:2.X.X'
    
  • 既然Retrofit是封装OkHttp的请求所以我们肯定得先配置OkHttp

    OkHttpClient.Builder builder = new OkHttpClient.Builder();
    // 设置超时时间
    builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
    builder.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
    builder.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
    // 添加缓存
    builder.cache(new Cache(cacheFile, CACHE_SIZE));
    //添加网络拦截器;
    builder.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
            .addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR);
    //添加token过期监听
    builder.authenticator(mAuthenticator);
    builder.retryOnConnectionFailure(true);
    builder = StethoUtils.configureInterceptor(builder);
    mOkHttpClient = builder.build();
    
  • 然后把我们构造好的OkHttpClient组装给Retrofit

    Retrofit mRetrofit = new Retrofit.Builder()
            .client(mOkHttpClient) // 添加OkHttp客户端
            .baseUrl(Constant.BASE_URL)
            .addConverterFactory(converterFactory) // 设置解析器
            .build();
    
  • 我们这里先简单示意一个请求接口类(只包含一个GET请求:获取某一页的emoji表情包)

    public interface RESTfulAPI {
            @GET("emoji")
            Call<List<EmojiBean>> getEmoji(@Query("page") int page);
    }
    
  • 最后用我们编写好的请求接口类完成Retrofit的构造

    Retrofit instance = mRetrofit.create(RESTfulAPI.class);
    
  • 最终我们发送请求的方式便是这样

    Call<List<EmojiBean>> emojiCall = instance.getEmoji(page);
    emojiCall.enqueue(new retrofit2.Callback<List<EmojiBean>>() {
            @Override 
            public void onResponse(Call<List<EmojiBean>> call , Response<List<EmojiBean>> response) {
                //TODO
            }
    
            @Override 
            public void onFailure(Call<List<EmojiBean>> call , Throwable t) {
                //TODO
            }
    });
    

至此,我们使用Retrofit通过OkHttp完成了一次请求

JSON API是什么
  • 何为JSON API格式
    Redtful API的设计中,数据的响应格式有很多种
    比如
    我们常见的API接口的返回格式 JSON + ret-data-msg
    类似这样

    {
        "ret": 200,
        "data": {
        "title": "Default Api",
        "content": "PHPer您好,欢迎使用PhalApi!",
        "version": "1.1.0",
        "time": 1423142802
        },
        "msg": ""
    }
    

    其中ret表示请求返回的状态码,data表示业务数据,msg为错误信息
    这种Restful API应该是最常见的

    但是这并不是一种严格定制的设计规范,更多是一种约定俗成

    • 在《RESTful Web APIs》一书中提及到,标准可以划归到4个分类,分别是:fiat标准、个人标准、公司标准以及开放标准; 而JSON + ret-data-msg 返回格式既不是个人标准,也不是公司标准,更不属于开放标准,只能算fiat标准
      —-统一的返回格式和结构:ret data msg

    • 从根本上说,好的 RESTful Api 应该:
      1.公开资源
      2.通过 HTTP,使用 HTTP 动词来操纵他们
      3.和提供了规范指向自己,以及链接到其他的相关资源
      —- PhlyRestfully - ZF2 module for creating RESTful JSON APIs

    显然我们常见的JSON + ret-data-msg这种返回响应格式并不是RESTful API的最好的响应格式

    除此之外我们还有一些具有严格开放标准的RESTful API的返回响应格式
    比如 HAL + JSON , JSON API

    我们这里所使用的JSON API规范,诞生与2013于2015年推出的1.0版本,模拟一个简单的例子

    {
      "data": {
      "type": "articles",
      "id": "1",
      "attributes": {
          //文章资源的各种属性
      },
      "relationships": {
          //该文章与其他资源的关系
      }
      "include": {
          //其他资源
      }
      }
    }
    

    优点与特性,可以看官网(JSON API)(JSON API设计用来最小化请求的数量,以及客户端与服务器间传输的数据量。在高效实现的同时,无需牺牲可读性、灵活性和可发现性)

    OK,到此我们可以这么理解,JSON API是一种规范高效的数据响应格式

如何利用Retrofit解析JSON API

官网上面其实已经推荐了很多JSON API的解析框架
在Java环境下有
jsonapi-converter
crnk.io
在Android环境下有
faogustavo/JSONApi
moshi-jsonapi
Morpheus
然而可以轻松集成进Retrofit的只有jsonapi-converter以及moshi-jsonapi

因为项目中使用的是jsonapi-converter,我们这里也使用他来下手吧

我们的目的是要将JSON API格式的数据转换为可用的POJO数据模型,所以我们首先应该根据JSON API来构造我们的POJO

模拟有这样一段JSON API格式的数据需要解析

  {
    "data": {
    "type": "articles",
    "id": "id",
    "attributes": {
    "title": "title"
    },
    "relationships": {
      "author": {
        "data": {
          "type": "people",
          "id": "id"
         }
      }
    }
  },
  "included": [
  {
    "type": "people",
    "id": "id",
    "attributes": {
      "firstName": "John"
    }
  }
  ]
}

我们需要编写的POJO便是如下

@Type("articles")
@JsonIgnoreProperties(ignoreUnknown = true)
public class ArticlesBean {
    @Id
    private int id;
    private String title;
    @Relationship("people")
    List<People> people;

    //getter and setter
}

----
@Type("people")
@JsonIgnoreProperties(ignoreUnknown = true)
public class PeopleBean{
    @Id
    private int id;
    private String firstName;
 }

周所周知,Retrofit有着强大的扩展性,我们需要做的只有在构造Retrofit客户端时调用addConverterFactory方法传入JSONAPI解析器即可

ObjectMapper objectMapper = new ObjectMapper();

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://yourapi")
//JSONAPIConverterFactory的构造参数包含一个对象映射器以及你需要解析的POJO类
.addConverterFactory(new JSONAPIConverterFactory(objectMapper, ArticlesBean.class, PeopleBean.class))
.build();

Retrofit instance = retrofit.create(MyBooksService.class);

最后在Retrofit的请求接口类里添上对于Articles的请求

@FormUrlEncoded
@Headers("Accept:application/vnd.lumendingo.v1+json.")
@GET("articles?include=people")
Call<JSONAPIDocument<ArticlesBean>> getArticles();

接下来只需照常发送请求,jsonapi-converter帮我们做了解析方面几乎或有工作,不只是我们需要的type实体,以及其meta,link, relationship,以及relationship的type实体,meta,link,所有include的数据只需遵循简单的规则编写下POJO类便可一步到位.(具体的规则当然是github主页去看啦)

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2019 All Rights Reserved.

访客数 : | 访问量 :