Android 网络框架 Retrofit2.0介绍、使用和封装

前言

时至今日,Android的网络框架不再像之前那么到处都是,随着Google把 HttpClient直接删掉,似乎意味着Android越来越成熟。网络框架中的佼佼者Volley也不再那么光鲜,取而代之的是 Retrofit 和 okHttp。

感觉很像 OnePiece 中白胡子的离去象征着时代的变革,新时代的开始,多弗的垮台象征着七武海制度的取缔一样,不会使用Retrofit + okHttp + RxJava等一系列技术,就迈不进新时代的门槛,也不足以称为一个合格的开发者。

哈哈闲话不多说了,只是在 Android这个平台上 开发这么长时间的一点感触。各位看看笑笑也就算了。还是来介绍 Retrofit 吧。(直接略过1.9)

本文的所有代码在 retrofitLearn;

1. Retrofit介绍

A type-safe HTTP client for Android and Java

一个用于Android和Java平台的类型安全的网络框架

Retrofit is a type-safe REST client for Android built by Square. The library provides a powerful framework for authenticating and interacting with APIs and sending network requests with OkHttp.

Retrofit 是一个Square开发的类型安全的REST安卓客户端请求库。这个库为网络认证、API请求以及用OkHttp发送网络请求提供了强大的框架 。

Retrofit 把REST API返回的数据转化为Java对象,就像ORM框架那样,把数据库内的存储的数据转化为相应的Java bean对象。

那么我们知道Retrofit是一个类型安全的网络框架,而且它是使用REST API的,接下来我们看看什么是REST吧。

2. REST 介绍:

Resources Representational State Transfer

资源表现层状态转化

  • 每一个URI代表一种资源
  • 客户端和服务器之间,传递这种资源的某种 表现层(“资源”具体呈现出来的形式,比如.txt,.png,.jpg)
  • 客户端通过四个HTTP动词(GET用来获取资源,POST用来新建或更新资源,PUT用来更新资源,DELETE用来删除资源)对服务器端资源进行操作,实现”表现层状态转化”

关于REST,这里只仅仅列出了结论,文末有超级好的链接,请查看。如果你所使用的API是REST的,那么恭喜你,这样的API看起来真的很舒服,庆幸的是我司就使用的是REST API。

知道了REST是什么,那接下啦就开始介绍Retrofit的用法啦。

3. Retrofit基本用法(未封装)

1.在build.gradle中添加依赖

//okHttp
compile ‘com.squareup.okhttp3:okhttp:3.2.0‘

//retrofit
compile ‘com.squareup.retrofit2:retrofit:2.0.2‘
compile ‘com.squareup.retrofit2:converter-gson:2.0.2‘
compile ‘com.squareup.okhttp3:logging-interceptor:3.2.0‘

2.创建接口,声明API

//Retrofit turns your HTTP API into a Java interface.
//创建接口,声明GitHub的API
public interface GitHubAPI {

     /*
       请求该接口:https://api.github.com/users/baiiu
     */
     @GET("users/{user}")
     Call<User> userInfo(@Path("user") String user);
}

3.在MainActivity.onCreate()方法中调用

/*
1.初始化OkHttpClient
*/
OkHttpClient client = new OkHttpClient();

/*
2.创建Retrofit
*/
retrofit = new Retrofit.Builder()
        //设置OKHttpClient
        .client(client)
        //设置baseUrl,注意,baseUrl必须后缀"/"
        .baseUrl("https://api.github.com/")

        //添加Gson转换器
        .addConverterFactory(GsonConverterFactory.create())
        .build();

/*
2.获取GitHub的API
*/
GitHubAPI gitHubAPI = retrofit.create(GitHubAPI.class);

/*
3.异步调用
*/
Call<User> userCall = gitHubAPI.userInfo("baiiu");
userCall.enqueue(new Callback<User>() {
      @Override public void onResponse(Call<User> call, Response<User> response) {
        User body = response.body();
        LogUtil.d(body == null ? "body == null" : body.toString());
      }

      @Override public void onFailure(Call<User> call, Throwable t) {
        /*
         判断是否被cancel掉了
        */
        if (call.isCanceled()) {
          LogUtil.d("the call is canceled , " + toString());
        } else {
          LogUtil.e(t.toString());
        }
      }
    });

/*
取消调用
*/
//userCall.cancel();

/*
同步调用,举个例子,写法如下(当然不能在主线程调用):
*/

//Each instance can only be used once, but calling clone() will create a new instance that can be used.
Call<User> clone = userCall.clone();

Response<User> response = clone.execute();
User body = response.body();
LogUtil.d(body == null ? "body == null" : body.toString());

注意:

1. 设置BaseUrl时必须后缀”/”,如 https://api.github.com/,这篇文章说的超清晰:Retrofit 2.0: The biggest update yet on the best HTTP Client Library for Android

2. 因为Retrofit在创建时候传入了BaseUrl,所以基本上所有请求都基于该BaseUrl了。但是总有些API不是以该BaseUrl开头的,特别是有些公司可能不是restful API的。那么该怎么办呢。Retrofit提供了一个注解@Url解决这个问题,可以在运行时直接使用该Url直接访问。代码如下:

//使用@Url注解,传入该Url地址就OK啦,跨过BaseUrl,直接访问该Url地址
@GET Call<Daily> getNewsList(@Url String url);

恩,接下来,知道了Retrofit的基本使用,接下来就是介绍Retrofit的注解了。

4. Retrofit注解

Retrofit使用注解来声明API的请求方式、请求参数等。这里只介绍一下它的 @Header 注解,其他的请阅读 官网文档 和 鸿洋的 Retrofit2 完全解析 探索与okhttp之间的关系。(这块写了也是翻译官方文档的和参考鸿样的,会拉长篇幅)

请求头的设置可以通过 @Header 注解添加,又有两种添加方式:

  • 设置静态的请求头。
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();

@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
  • 动态的设置请求头。
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

Note that headers do not overwrite each other. All headers with the same name will be included in the request.

同一个请求的同一个请求头在不同地方的设置不会被覆盖,而是会被全部添加进请求头中。

Headers that need to be added to every request can be specified using an OkHttp interceptor.

如果要给每个请求都添加同样的Header时,可以使用okHttp的 Interceptor

那么,接下来就介绍Interceptor。

5.Interceptors使用

Retrofit 2.0 底层强制依赖okHttp,所以可以使用okHttp的拦截器Interceptors 来对所有请求进行再处理。

Interceptors are a powerful mechanism that can monitor, rewrite, and retry calls.

使用时,实现 Interceptor 接口,做我们自己的处理。

目前使用中,一般用来设置UA设置缓存策略打印Log 等。这里介绍一个设置UA的Interceptor:

1.创建设置UA的Interceptor

public final class UserAgentInterceptor implements Interceptor {
  private static final String USER_AGENT_HEADER_NAME = "User-Agent";
  private final String userAgentHeaderValue;

  public UserAgentInterceptor(String userAgentHeaderValue) {
    this.userAgentHeaderValue = userAgentHeaderValue;
  }

  @Override public Response intercept(Chain chain) throws IOException {
    final Request originalRequest = chain.request();

    final Request requestWithUserAgent = originalRequest.newBuilder()

        //移除先前默认的UA
        .removeHeader(USER_AGENT_HEADER_NAME)

        //设置UA
        .addHeader(USER_AGENT_HEADER_NAME, userAgentHeaderValue)

        .build();
    return chain.proceed(requestWithUserAgent);
  }
}

2.创建okHttpClient时 设置该Interceptor

okHttpClient = new OkHttpClient.Builder()
        //添加UA
        .addInterceptor(new UserAgentInterceptor(HttpHelper.getUserAgent()))

        //失败重连
        .retryOnConnectionFailure(true)

        //time out
        .readTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
        .connectTimeout(TIMEOUT_CONNECTION, TimeUnit.SECONDS)

        .build();

Interceptors 和 Header 的配合使用让我们很方便的使用Http本身的缓存。之前用Volley的时候这块就比较难处理。解下来就说说Retrofit的缓存机制。

6. 配置网络缓存

使用Retrofit 感觉最方便的就是它提供的缓存方式(虽然这是Http本身的),我们可以随便通过Header和Interceptor配置自己的缓存策略。

6.1 缓存设置原理:

缓存的设置是通过设置 Http请求头和响应头中的 Cache-Controlmax-age 属性达到的。在复写 Interceptor 时,通过设置响应头的 Cache-Control 来达到目的。关于Http的本身的缓存命中请查看文末链接 (毕竟Http也是个大家伙) 。

6.2 缓存设置步骤

  1. 设置缓存目录

    retrofit本身默认无缓存,连缓存目录都没有提供默认的,所以 要想实现缓存,必须要在创建OkHttpClient时设置缓存目录。 这块超级坑,自己试了半天,最终看了下Cache那边的源码,竟然没有默认的缓存目录!!!

  2. 设置缓存的方式
    • 通过添加 @Headers("Cache-Control: max-age=120") 进行设置。添加了Cache-Control 的请求,retrofit 会默认缓存该请求的返回数据。
    • 通过Interceptors实现缓存。

6.3 实现Interceptor进行缓存

提供了两种缓存策略(参考),设置缓存时Application Interceptor 和 Net Interceptor 都要设置:

  • AllCachedInterceptor

    有网没网都先走缓存,可以设置间歇时间。

    同时可以针对某一个request设置单独的缓存时间,使用 @Headers("Cache-Control: max-age=120") 就行。

  • OnOffLineCachedInterceptor

    有网可以不走缓存,可设定时间,设置为0意味着有网不走缓存,全部刷新数据;无网强制读取缓存数据。

到现在为止,关于Retrofit的基本用法和缓存设置已经了解了,写点例子就已经会用了,接下来肯定就是进行封装了,让它更便于调用。

7. Retrofit 封装

封装Retrofit是为了提供更方便的调用,更好的配置和使用。那么看到开头的Retrofit调用方式,大概有这么几个步骤:

1. 创建OkHttpClient

2. 创建Retrofit实例

3. 获取我们写的API interface

4. 在代码中异步调用

那么封装时候也肯定从这几步入手:

7.1 初始化OkHttpClient

创建OkHttpFactory类,初始化OkHttpClient并对外提供该实例的单例。并提供一个 HttpHelper 类用于提供所需要的参数,比如UA。

这样做的好处是,程序中会使用OkHttp做一些其他请求操作,比如下载、上传等网络操作,就可用共用一个OkHttpClient。

这里使用枚举生成单例。

enum OKHttpFactory {

  INSTANCE;

  private final OkHttpClient okHttpClient;

  private static final int TIMEOUT_READ = 25;
  private static final int TIMEOUT_CONNECTION = 25;

  OKHttpFactory() {
    //打印请求Log
    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

    //缓存目录
    Cache cache = new Cache(MyApplication.mContext.getCacheDir(), 10 * 1024 * 1024);

    okHttpClient = new OkHttpClient.Builder()
        //打印请求log
        .addInterceptor(interceptor)

        //stetho,可以在chrome中查看请求
        .addNetworkInterceptor(new StethoInterceptor())

        //添加UA
        .addInterceptor(new UserAgentInterceptor(HttpHelper.getUserAgent()))

        //必须是设置Cache目录
        .cache(cache)

        //走缓存,两个都要设置
        .addInterceptor(new OnOffLineCachedInterceptor())
        .addNetworkInterceptor(new OnOffLineCachedInterceptor())

        //失败重连
        .retryOnConnectionFailure(true)

        //time out
        .readTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
        .connectTimeout(TIMEOUT_CONNECTION, TimeUnit.SECONDS)

        .build();
  }

  public OkHttpClient getOkHttpClient() {
    return okHttpClient;
  }
}

7.2 初始化Retrofit

依然使用枚举创建单例:

public enum RetrofitClient implements ApiContants {
  INSTANCE;

  private final Retrofit retrofit;

  RetrofitClient() {
    retrofit = new Retrofit.Builder()
        //设置OKHttpClient
        .client(OKHttpFactory.INSTANCE.getOkHttpClient())

        //baseUrl
        .baseUrl(GITHUB_BASEURL)

        //gson转化器
        .addConverterFactory(GsonConverterFactory.create())

        .build();
  }

  public Retrofit getRetrofit() {
    return retrofit;
  }
}

7.3 创建ApiFactory类封装所有API

如题,创建ApiFactory类管理所有的API interface,对外提供方法获取他们,这样调用时会方便很多,而且也便于修改。

public enum ApiFactory {
  INSTANCE;

  private final GitHubAPI gitHubAPI;
  private final AnotherAPI anotherAPI;

  ApiFactory() {
    gitHubAPI = RetrofitClient.INSTANCE.getRetrofit().create(GitHubAPI.class);
    anotherAPI = RetrofitClient.INSTANCE.getRetrofit().create(AnotherAPI.class);
  }

  public GitHubAPI gitHubAPI() {
    return gitHubAPI;
  }

  public AnotherAPI getAnotherAPI() {
    return anotherAPI;
  }
}

这样封装在外部调用时会方便很多,比如:

    Call<User> userCall = ApiFactory.gitHubAPI().userInfo("baiiu");

封装的代码在GitHub上:retrofitLearn;

这样封装自己觉得还不错,就可以开心的写代码啦。接下来说说一个神奇的工具。

8. Stetho 一个神奇的工具

首先:使用该工具需要翻墙。 不能翻墙的还是使用Charles吧。

  1. gradle中添加:
  compile ‘com.facebook.stetho:stetho:1.3.1‘
  compile ‘com.facebook.stetho:stetho-okhttp3:1.3.1‘
  1. 打开chrome,输入chrome://inspect

    点击你的程序进行inspect,就可以直接使用Chrome进行抓包、调试你的应用啦。但是不能翻墙的话,你会看到一片空白。。。

结语:

毕竟Retrofit出来已经很久了,没有的赶紧用用吧。在使用Retrofit时,深深赶紧到其对Http本身机制的应用之深,真的感觉到非常棒的应用体验。用Retrofit作为网络框架,简直就能感觉到它设计之美,更何况还能和RxJava结合起来,美到不行。

参考:这些参考都值得一看的

时间: 2024-07-30 20:23:37

Android 网络框架 Retrofit2.0介绍、使用和封装的相关文章

Android网络之Retrofit2.0使用和解析

Android网络之Retrofit2.0使用和解析 Retrofit2在项目中的使用 Android studio项目添加依赖 compile 'com.squareup.retrofit2:retrofit:2.0.1' 项目中使用样例 定义HTTP API使用接口 public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path(&quo

ym—— Android网络框架Volley(体验篇)

<a target=_blank href="https://android.googlesource.com/platform/frameworks/volley" style="font-family: Arial, Helvetica, sans-serif; box-sizing: border-box; background-image: initial; background-attachment: initial; background-color: rg

Android网络框架Volley

Volley是Google I/O 2013推出的网络通信库,在volley推出之前我们一般会选择比较成熟的第三方网络通信库,如: android-async-http retrofit okhttp 他们各有优劣,之前个人则比较喜欢用Android-async-http, 如今Google推出了官方的针对Android平台上的网络通信库,能使网络通信更快,更简单,更健壮,Volley在提供了高性能网络通讯功能的同时,对网络图片加载也提供了良好的支持,完全可以满足简单REST客户端的需求, 我们

教你写Android网络框架之Http请求的分发与执行

前言 在<教你写Android网络框架>专栏的前两篇博客中,我们已经介绍了SimpleNet框架的基本结构,以及Request.Response.请求队列的实现,以及为什么要这么设计,这么设计的考虑是什么.前两篇博客中已经介绍了各个角色,今天我们就来剖析另外几个特别重要的角色,即NetworkExecutor.HttpStack以及ResponseDelivery,它们分别对应的功能是网络请求线程.Http执行器.Response分发,这三者是执行http请求和处理Response的核心. 我

教你写Android网络框架之Request、Response类与请求队列

转载请注明出处,本文来自[ Mr.Simple的博客 ]. 我正在参加博客之星,点击这里投我一票吧,谢谢~ 前言 在教你写Android网络框架之基本架构一文中我们已经介绍了SimpleNet网络框架的基本结构,今天我们就开始从代码的角度来开始切入该网络框架的实现,在剖析的同时我们会分析设计思路,以及为什么要这样做,这样做的好处是什么.这样我们不仅学到了如何实现网络框架,也会学到设计一个通用的框架应该有哪些考虑,这就扩展到框架设计的范畴,通过这个简单的实例希望能给新人一些帮助.当然这只是一家之言

android 网络框架 源码分析

android 网络框架 源码分析 导语: 最近想开发一个协议分析工具,来监控android app 所有的网络操作行为, 由于android 开发分为Java层,和Native层, 对于Native层我们只要对linux下所有网络I/O接口进行拦截即可,对于java 层,笔者对android 网络框架不是很了解,所以这个工具开发之前,笔者需要对android 的网络框架进行一个简单的分析. 分析结论: 1. android 的网络框架都是基于Socket类实现的 2. java 层Socket

Android网络框架OKhttp3学习笔记

OKhttp3是一个非常强大的Android网络框架,它是由Square公司开发并开源的,很大Android开发者都会使用到,所以我也要来学学. 服务器 为了方便测试,我们需要一个后台服务器的的应用,下面是一个Java Web的Servlet,它的功能是接收客户端发来的登录数据,判断密码是否正确,并返回结果(JSON格式) import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; impo

Android 网络框架 android-async-http

转载请注明出处:明桑Android 这是Android网络框架系列的最后一篇了~~, 文章主要介绍第三方库 android-async-http的使用,之后作为Android网络框架系列的完结,对在开发中如何学习和使用第三方框架做个总结! 1,Android Asynchronous Http Client简介 android-async-http是封装了HttpClient的顶层实现,它所发起的Request全部运行于不同于UI线程的其它线程中,但它回调的处理逻辑和使用Handler发送mes

Android网络框架-Volley实践 使用Volley打造自己定义ListView

这篇文章翻译自Ravi Tamada博客中的Android Custom ListView with Image and Text using Volley 终于效果 这个ListView呈现了一些影视信息,每一行是一个影片的信息,每一行中有一张电影的图片,电影的名字.评分.类型.年份等信息. 1.json数据 我们通过解析json然后拿到数据,这个json数据包含json数组.每一个json数组中是一个json对象,json对象中包含了电影的图片url地址.标题.年份.评分.类型等信息 JSO