Retrofit 使用 一
来源:互联网 发布:dota 知乎 编辑:程序博客网 时间:2024/05/17 18:14
前言
时至今日,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
资源表现层状态转化
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-gson Jackson - com.squareup.retrofit2:converter-jackson Moshi - com.squareup.retrofit2:converter-moshi Protobuf - com.squareup.retrofit2:converter-protobuf Wire - com.squareup.retrofit2:converter-wire Simple Framework - com.squareup.retrofit2:converter-simpleframework Scalars - com.squareup.retrofit2:converter-scalars LoganSquare - com.github.aurae.retrofit2:converter-logansquare FastJson - 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>(){ @Override public void onResponse(Call<User> call, Response<User> response) { Log.i(TAG, "name: " + response.body().login + " id: " + response.body().id); } @Override public 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=username http://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") @FormUrlEncoded Call<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
请求头的设置可以通过
设置静态的请求头。@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的 。
5 配置OkHttpClient
由于Retrofit 2.0 底层强制依赖okHttp,所以可以使用okHttp的拦截器Interceptors 来对所有请求进行再处理。目前使用中,一般用来、 、 等。这里介绍下配置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>() { @Override public 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); } @Override public void onFailure(Call<User> call, Throwable t) { } });
代码github 地址:https://github.com/nickyangjun/RetrofitTest
未完待续,下节将会从源码角度分析Retrofit。
- Retrofit使用教程(一)
- Retrofit 使用 一
- Retrofit使用教程(一)
- Retrofit使用教程(一)
- Retrofit的使用【一】
- Retrofit使用一
- Retrofit的使用教程(一)
- Android Retrofit使用(一)
- Retrofit使用教程(一)- Retrofit入门详解
- Retrofit使用教程(一)- Retrofit入门详解
- Retrofit使用一:超简单先用上
- Android Retrofit使用教程(一)
- Retrofit的使用详解(一)
- RxJava+Retrofit+OkHttp 懒人方式使用一
- RxJava+Retrofit+OkHttp 懒人方式使用一
- Retrofit的使用教程(一) 1.9
- Retrofit的简单使用(一)
- retrofit<一>
- HDU 5514 Frogs(容斥)
- HTML5 WebSocket和后端C#通信
- UNIT TEST
- Mysql索引会失效的几种情况分析
- 原型链机制简述
- Retrofit 使用 一
- Glide加载图片并保存到本地相册
- DUNS及苹果开发者账号申请
- 策略模式(Strategy)
- Android5.0之Toobar的使用
- window.opener 与 window.parent 的区别
- matlab与c#混合编程之图像参数传递
- 记录自己学习遇到的问题
- 数组中重复元素的问题