Retrofit 使用 一
前言
时至今日,Android的网络框架不再像之前那么到处都是,随着Google把 HttpClient直接删掉,似乎意味着Android越来越成熟。网络框架中的佼佼者Volley也不再那么光鲜,取而代之的是 Retrofit 和 okHttp。如今不会使用Retrofit + okHttp + RxJava等一系列技术,就迈不进新时代的门槛,跟不上时代的步伐。
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发送网络请求提供了强大的框架 。
You’ll use annotations to describe HTTP requests, URL parameter replacement and query parameter support is integrated by default. Additionally, it provides functionality for multipart request body and file uploads.
你可以使用注释来描述HTTP请求,URL参数替换和查询参数都默认支持。此外,它还支持多请求体和文件上传功能。
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 指的是一组架构约束条件和原则,满足这些约束条件和原则的应用程序或设计就是 RESTful。REST 描述了一个架构样式的互联系统(如 Web 应用程序)。REST 约束条件作为一个整体应用时,将生成一个简单、可扩展、有效、安全、可靠的架构。
知道了REST是什么,那接下啦就开始介绍Retrofit的用法啦。
retrofit2官网地址:https://github.com/square/retrofit/
3. Retrofit基本用法
1.在build.gradle中添加依赖
compile 'com.squareup.retrofit2:retrofit:2.1.0'compile 'com.squareup.retrofit2:converter-gson:2.1.0'
目前最新版为2.1.0, 同时为了支持将网络请求转化成java bean对象,我们这里使用了gson,所以也需要在gradle里添加依赖。当然除了gson以外,还提供了以下的选择:
Gson - com.squareup.retrofit2:converter-gsonJackson - com.squareup.retrofit2:converter-jacksonMoshi - com.squareup.retrofit2:converter-moshiProtobuf - com.squareup.retrofit2:converter-protobufWire - com.squareup.retrofit2:converter-wireSimple Framework - com.squareup.retrofit2:converter-simpleframeworkScalars - com.squareup.retrofit2:converter-scalarsLoganSquare - com.github.aurae.retrofit2:converter-logansquareFastJson - org.ligboy.retrofit2:converter-fastjson or org.ligboy.retrofit2:converter-fastjson-android
当然也支持自定义,你可以选择自己写转化器完成数据的转化,这个后面将具体介绍。
2.创建接口,声明API
public interface GitHubUserInfo {@GET("users/{user}")Call<User> getUserInfo(@Path("user") String user);
}
这里我们以获取github开放的用户信息https://api.github.com/users/xxx 为例,注意retrofit能把接口返回的json直接转成bean对象,所以我们还需自己定义了User对象。这里略过User对象的代码。可以看到上面有一个getUserInfo()方法,通过@GET
注解标识为get请求,@GET
中所填写的value和baseUrl
将组成成完整的路径,baseUrl
在构造retrofit对象时给出。Retrofit提供了5种内置的注解:GET
、POST
、PUT
、DELETE
和HEAD,
在注解中指定URL的路径和查询参数,上面的{user}代表动态替换块,可以在使用时通过getUserInfo方法中@Path注解的参数替换,注意使用@Path修饰的参数必须与{}里的参数一样,这里都是“user”字符串。
3. 创建Retrofit
/*** 创建Retrofit*/Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com/") //设置baseUrl,注意,baseUrl必须后缀"/".addConverterFactory(GsonConverterFactory.create()) //添加Gson转换器.build();
4. 获取GitHubUserInfo的实例
/*** 获取GitHubUserInfo的实例*/GitHubUserInfo userInfo = retrofit.create(GitHubUserInfo.class);
ok,这里很神奇,我们通过Retrofit.create
就可以拿到我们定义的GitHubUserInfo的实例,调用其方法即可拿到一个Call
对象,通过call.enqueue
即可完成异步的请求。
5.异步调用
/*** 异步调用*/Call<User> userCall = userInfo.getUserInfo("nickyangjun");userCall.enqueue(new Callback<User>(){@Overridepublic void onResponse(Call<User> call, Response<User> response) {Log.i(TAG, "name: " + response.body().login + " id: " + response.body().id);}@Overridepublic void onFailure(Call<User> call, Throwable t) {}});
需要注意的是每一个Call实例都可以同步call.excute()或者异步call.enquene(CallBack<?> callBack)的被执行,每一个实例仅仅能够被使用一次,但是可以通过clone()函数创建一个新的可用的实例。而且异步调用时上面的执行结果是在主线程中回调的,这点很方便我们更新UI操作。Retrofit默认是使用OKHttp网络请求框架来实现的网络请求操作的。并且2.0版本中支持请求取消,取消请求只需调用call.cancel()。
4. Retrofit注解
上面只是简单演示了Retrofit的get请求功能,同时上面也用到了@Path注解,Retrofit的请求注解还有许多更强大的功能,比如:
1 @Query
查询参数的设置,先看下面的url:
http://baseurl/users?sortby=usernamehttp://baseurl/users?sortby=id
即一般的传参,我们可以通过@Query注解方便的完成,我们再次在接口中添加一个方法:
@GET("users")Call <List<User>> getUserInfoBySort(@Query("sortby") String sort);
这里我们返回的是一个list<User>对象。调用时也跟前面调用方法一样:
//省略前面retrofit构建的代码GitHubUserInfo userInfo = retrofit.create(GitHubUserInfo.class);Call <List<User>> usersListCall = userInfo.getUserInfoBySort("id");//省略后面call执行的代码
这样我们就完成了参数的指定,当然相同的方式也适用于POST,只需要把注解修改为@POST即可。对了,我上面学了@PATH,那么会不会有这样尝试的冲动,对于刚才的需求,我们这么写:
@GET("users?sortby={sortby}")Call<List<User>> getUsersBySort(@Path("sortby") String sort);
看上去没有问题,哈,实际上运行是不支持的~估计是@ Path的定位就是用于url的路径而不是参数,对于参数还是选择通过@Query来设置。
2 @Body
POST请求体的方式向服务器传入json字符串,
大家都清楚,我们app很多时候跟服务器通信,会选择直接使用POST方式将json字符串作为请求体发送到服务器,那么我们看看这个需求使用retrofit该如何实现。
再次添加一个方法:
@POST("add")Call<User> addUser(@Body User user);
调用post提交的代码基本都是一致的:
//省略前面构建retrofit的代码GitHubUserInfo userInfo = retrofit.create(GitHubUserInfo.class);Call <User> addUser = userInfo.addUser(new User(123,"nick"));//省略后面Call执行的代码
ok,可以看到其实就是使用@Body这个注解标识我们的参数对象即可,那么这里需要考虑一个问题,retrofit是如何将user对象转化为字符串呢?下文将详细解释~
3 @FormUrlEncoded
表单的方式传递键值对
这里我们模拟一个登录的方法,添加一个方法:
@POST("login")@FormUrlEncodedCall<User> login(@Field("username") String username, @Field("password") String password);
提交的代码:
//省略前面构建retrofit的代码GitHubUserInfo userInfo = retrofit.create(GitHubUserInfo.class);Call <User> loginUser = userInfo.login("nick","123456");//省略后面Call执行的代码
ok,看起来也很简单,通过@POST
指明url,添加FormUrlEncoded
,然后通过@Field
添加参数即可。
4 @Multipart
单文件上传
下面看一下单文件上传,依然是再次添加个方法:
@Multipart@POST("register")Call<User> registerUser(@Part MultipartBody.Part photo, @Part("username") RequestBody username, @Part("password") RequestBody password);
这里@MultiPart的意思就是允许多个@Part了,我们这里使用了3个@Part,第一个我们准备上传个文件,使用了MultipartBody.Part类型,其余两个均为简单的键值对。 下面是调用:
//省略前面构建retrofit的代码GitHubUserInfo userInfo = retrofit.create(GitHubUserInfo.class);File file = new File(Environment.getExternalStorageDirectory(), "icon.png");RequestBody photoRequestBody = RequestBody.create(MediaType.parse("image/png"), file);MultipartBody.Part photo = MultipartBody.Part.createFormData("photos", "icon.png", photoRequestBody);Call<User> call = userInfo.registerUser(photo, RequestBody.create(null, "abc"), RequestBody.create(null, "123"));//省略后面Call执行的代码
ok,这里感觉略为麻烦。不过还是蛮好理解~~多个@Part,每个Part对应一个RequestBody。
5 @PartMap
多文件上传,再添加一个方法~~~
@Multipart @POST("register") Call<User> registerUser(@PartMap Map<String, RequestBody> params);
这里使用了一个新的注解@PartMap,这个注解用于标识一个Map,Map的key为String类型,代表上传的键值对的key(与服务器接受的key对应),value即为RequestBody,有点类似@Part的封装版本。
执行的代码:
//省略前面构建retrofit的代码GitHubUserInfo userInfo = retrofit.create(GitHubUserInfo.class);File file = new File(Environment.getExternalStorageDirectory(), "icon.png");RequestBody photoRequestBody = RequestBody.create(MediaType.parse("image/png"), file);Map<String,RequestBody> photos = new HashMap<>();photos.put("photos\"; filename=\"icon.png", photoRequestBody);photos.put("username", RequestBody.create(null, "abc"));photos.put("password", RequestBody.create(null, "123"));Call<User> call = userInfo.registerUser(photos);//省略后面Call执行的代码
可以看到,可以在Map中put进一个或多个文件,键值对等,当然你也可以分开,单独的键值对也可以使用@Part,这里又看到设置文件的时候,相对应的key很奇怪,例如上例"photos\"; filename=\"icon.png",前面的photos就是与服务器对应的key,后面filename是服务器得到的文件名,ok,参数虽然奇怪,但是也可以动态的设置文件名,不太影响使用~~
6 @Header
请求头的设置可以通过 @Header 注解添加,又有两种添加方式:
设置静态的请求头。
@Headers({ "Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-Sample-App" })@GET("users/{user}")Call<User> getUserInfo(@Path("user") String user);
动态的设置请求头。
@GET("user") Call getUser(@Header("Authorization") String authorization);
注意,同一个请求的同一个请求头在不同地方的设置不会被覆盖,而是会被全部添加进请求头中。
如果要给每个请求都添加同样的Header时,可以使用okHttp的 Interceptor
。
5 配置OkHttpClient
由于Retrofit 2.0 底层强制依赖okHttp,所以可以使用okHttp的拦截器Interceptors 来对所有请求进行再处理。目前使用中,一般用来设置UA、设置缓存策略 、打印Log 等。这里介绍下配置OkHttpClient和设置UserAgent的Interceptor:
public class OkHttpFactory {private OkHttpClient client;private static final int TIMEOUT_READ = 25;private static final int TIMEOUT_CONNECTION = 25;Cache cache = new Cache(MyApplication.mContext.getCacheDir(), 10 * 1024 * 1024);//缓存目录private OkHttpFactory(){client = new OkHttpClient.Builder().cache(cache).addInterceptor(new LoggingInterceptor()) //打印log.addInterceptor(new UserAgentInterceptor()) //UserAgent设置.retryOnConnectionFailure(true) //失败重连.readTimeout(TIMEOUT_READ, TimeUnit.SECONDS).connectTimeout(TIMEOUT_CONNECTION, TimeUnit.SECONDS).build();}public static OkHttpClient getOkHttpClient(){return Holder.INSTANCE.client;}private static class Holder{final public static OkHttpFactory INSTANCE = new OkHttpFactory();}
}
这里用单例实现了OkHttpClient,并且添加了缓存和超时设置,下面看看UserAgentInterceptor拦截器代码:
public 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 {Request originalRequest = chain.request();Request requestWithUserAgent = originalRequest.newBuilder().removeHeader(USER_AGENT_HEADER_NAME) //移除先前默认的User-Agent.addHeader(USER_AGENT_HEADER_NAME, userAgentHeaderValue) //设置新的User-Agent.build();return chain.proceed(requestWithUserAgent);}
}
下面将上面的OkHttpClient设置进Retrofit里:
public enum RetrofitClient {INSTANCE;private final Retrofit retrofit;RetrofitClient() {retrofit = new Retrofit.Builder()//设置OKHttpClient.client(OkHttpFactory.getOkHttpClient())//baseUrl.baseUrl(ApiContants.GITHUB_BASEURL)//gson转化器.addConverterFactory(GsonConverterFactory.create())//创建.build();}public Retrofit getRetrofit() {return retrofit;}
}
这里使用了枚举单例实现了Retorfit的一个Client,后续就可以轻松使用它了。如下面使用:
public interface GitHubAPI {@GET("user")Call<List<User>> getUser();@GET("users/{user}")Call<User> getUserInfo(@Path("user") String user);
}
public enum ApiFactory {INSTANCE;private static GitHubAPI gitHubAPI;ApiFactory() {}public static GitHubAPI gitHubAPI() {if (gitHubAPI == null) {gitHubAPI = RetrofitClient.INSTANCE.getRetrofit().create(GitHubAPI.class);}return gitHubAPI;}
}
最后使用创建ApiFactory类管理所有的API interface,对外提供方法获取他们,这样调用时会方便很多,而且也便于修改。调用如下:
Call<User> userCall = ApiFactory.gitHubAPI().getUserInfo("nickyangjun");userCall.enqueue(new Callback<User>() {@Overridepublic void onResponse(Call<User> call, Response<User> response) {Log.i(TAG, "name: " + response.body().login + " id: " + response.body().id);mTextView.setText("name: " + response.body().login + " id: " + response.body().id);}@Overridepublic void onFailure(Call<User> call, Throwable t) {}});
代码github 地址:https://github.com/nickyangjun/RetrofitTest
未完待续,下节将会从源码角度分析Retrofit。
Retrofit 使用 一相关推荐
- 为什么要使用Retrofit封装OkHttp,而不单独使用OkHttp?
OkHttp的优点: 开源的轻量级框架.高效.快速的请求客户端,可以单独使用它来实现网络请求. 支持SPDY: 支持连接池,可极大减少延时: 支持Gzip压缩响应体,降低传输内容的大小: 支持Http ...
- Retrofit 网络请求参数注解@Path @Field @Query 等使用
请求参数呢大致如下,到个别人的图, 下面就说下这些内容使用 其中 @Path.@Query.@QueryMap 使用 Get 请求 , 加入使用了Post 请求注解使用@Path 一般都会是项目崩溃 ...
- retrofit 源码分析
callAdater可以设置RxJava2CallAdapter,目前只可用这个adapter,支持rxjava2的操作:convertAdater可以使用多种进行操作. 调用例子: Retrofit ...
- Retrofit源码研究
2016-05-06 15:35:27 最近抽空研究了一下Retrofit源码,包括API使用.源码结构.使用到的设计模式.SDK的架构设计.作者设计/实现思路等,会形成一系列文章. 以前Retrof ...
- java dagger2_从零开始搭建一个项目(rxJava+Retrofit+Dagger2) ---上
工程结构 Androd studio 替代eclipse给我带来最大的感觉,就是不用每次需要用到什么类库,就得去网上下载一个jar包.只要在项目app/build.gradle中加入代码,就能远程使用 ...
- android 添加头参数,Retrofit添加header参数的几种方法
(1)使用注解的方式 添加一个Header参数 publicinterfaceUserService { @Headers("Cache-Control: max-age=640000&qu ...
- Spring Boot 中的 RestTemplate不好用?试试 Retrofit !
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者 | 六点半起床 来源 | juejin.im/post/68 ...
- 一行代码实现Okhttp,Retrofit,Glide下载上传进度监听
2019独角兽企业重金招聘Python工程师标准>>> 发表上篇文章 我一行代码都不写实现Toolbar!你却还在封装BaseActivity? 已是一个月前的事情~ 上篇文章的研究 ...
- java 获取动态的service_【Android】动态代理在 Retrofit 中的使用
首先,什么是动态代理和为什么会有动态代理. 众所周知,Java 是一门静态语言,编写完的类,无法在运行时做动态修改. 一个简单的动态代理如下: 1.先定义一个接口,想要使用动态代理,必须先定义一个接口 ...
- Retrofit全攻略——进阶篇
最近事比较多,距离上次写文章已经过去了一个月了.上一篇文章Retrofit全攻略--基础篇 介绍了Retrofit的基础用法,这篇文章介绍点进阶的用法. 打印网络日志 在开发阶段,为了方便调试,我们需 ...
最新文章
- JavaScript文本框的操作
- 服务 进程守护 MarsDaemon 简介
- jQuery教程10-表单元素选择器
- linux sort多磁盘排序,linux shell sort多字段排序
- vscode上传GitHub
- 在linux命令行利用SecureCRT上传下载文件
- jQuery 提供了多种遍历 DOM 的方法。 遍历方法中最大的种类是树遍历(tree-traversal)。jQuery 提供了多种遍历 DOM 的方法。 遍历方法中最大的种类是树遍历(tree-t
- python向mysql插入数据
- Mirai qq机器人框架kotlin/java教程
- logistic回归分析优点_数据统计的理解和应用(十二)多因素logistic回归案例分析...
- 2021年中国上牌和驾驶员数量分析:新注册登记机动车3674万辆 新领证驾驶人2750万人[图]
- python upd接收数据+动态折线图+线程间通信+字节计算
- 手写签名 PNG 制作
- Linux从头学09:x86 处理器如何进行-层层的内存保护?
- 休闲卤味的商业江湖里,周黑鸭的巨变与出路
- 单片机交通灯灯c语言程序,关于LED模拟交通灯单片机C语言程序设计 - 全文
- 攻略-联想 Yoga 900 安装 Arch Linux 系统
- 混迹在腾讯微博的知名站长名单
- VMware Workstation Pro16 的下载与安装
- PaperTigerOS(第四天)
热门文章
- Pygame实战:升级后的2048小游戏—解锁新花样,根本停不下来【附源码】
- C/C++使用Quirc库解析二维码(QRcode)
- docker+docker-compose部署微服务项目
- 计算机模拟技术 意义,喷丸数值模拟技术的研究意义和发展
- Hexo(sakura)添加RSS订阅
- java小游戏大鱼吃小鱼入门(15min写一个小游戏)
- matlab 反激实例(S440_Flyback.slx)
- 南加州大学林禹臣:教机器学习常识,是种什么体验?
- YOLOv2---优图代码+实现细节
- 重复读取输入流InputStream