随着Google对OKHTTP的强势推动,和Volley的逐渐没落,而Retrofit也对okHttp进行了强制依赖。
Retrofit是由Square公司出品的针对于Android和Java的类型安全的Http客户端,Retrofit其实质上就是对okHttp的封装,使用面向接口的方式进行网络请求,利用动态生成的代理类封装了网络接口请求的底层,
其将请求返回javaBean,对网络认证 REST API进行了很好的支持,使用Retrofit将会极大的提高我们应用的网络体验.
REST(REpresentational State Transfer)是一组架构约束条件和原则。
RESTful架构都满足以下规则:
(1)每一个URI代表一种资源;
(2)客户端和服务器之间,传递这种资源的某种表现层;
(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现”表现层状态转化”
依赖方式: compile 'com.squareup.retrofit2:retrofit:2.2.0’最新的版本号为2.2.0
Retrofit还提供以下几种Converter(转换器):
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 XML: com.squareup.retrofit2:converter-simplexml
Scalars (primitives,boxed,andString): com.squareup.retrofit2:converter-scalars
后边介绍这几种转换器。。。
Retrofit会默认提供一个OKHttpClient实现 也可以关联okhttp3创建一个okhttpclient客户端
在使用Retrofit前,我们需要先创建Retrofit实例,并且做一系列配置,然而Retrofit设计的也是非常好,这些配置都是可插拔的:
Retrofit retrofit = new Retrofit.Builder()
//设置baseUrl,注意baseUrl 应该以/ 结尾。
.baseUrl("http://news-at.zhihu.com/api/4/")
//使用Gson解析器,可以替换其他的解析器
.addConverterFactory(GsonConverterFactory.create())
//设置OKHttpClient,如果不设置会提供一个默认的
.client(new OkHttpClient())
//.client(new UrlConnectionClient())
//.client(new ApacheClient())
//.client(new CustomClient())
.build();
Retrofit 背后的 HTTP client,以及序列化机制(JSON/XML 协议)等都是可以替换,因此你可以选择自己合适的方案。Retrofit 最早出来的时候,只支持 Apache 的 HTTP client。后来增加了 URL connection,以及 OkHttp 的支持。如果你想使用其他的 HTTP client,可以通过以下方式了替换,或者更改为自定义的HTTP client:
//设置OKHttpClient,如果不设置会提供一个默认的
.client(new OkHttpClient())
//.client(new UrlConnectionClient())
//.client(new ApacheClient())
//.client(new CustomClient())
序列化功能也是可替换的。默认是用的 GSON,你当然也可以用 Jackson 来替换掉。转换器Converter上边都有写了,可以添加多种序列化Factory,但是GsonConverterFactory必须放在最后,否则会抛出异常(非常重要)。
//使用Gson解析器,可以替换其他的解析器
.addConverterFactory(GsonConverterFactory.create())
//当需要返回原始String数据时
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
addCallAdapterFactory提供RxJava支持,如果没有提供响应的支持(RxJava,Call),则会跑出异常。
2.0使用介绍
注意:retrofit2.0后:BaseUrl要以/结尾;@GET 等请求不要以/开头;@Url: 可以定义完整url,不要以 / 开头。
关于URL拼接注意事项:Retrofit 2.0:有史以来最大的改进
Retrofit注解:
方法注解:
包含@GET、@POST、@PUT、@DELETE、@PATH、@HEAD、@OPTIONS、@HTTP。
标记注解:
包含@FormUrlEncoded、@Multipart、@Streaming。
参数注解:
包含@Query,@QueryMap、@Body、@Field,@FieldMap、@Part,@PartMap。
其他注解:
@Path、@Header,@Headers、@Url
Retrofit通过注解实现了参数绑定 类型绑定 使用注解表明了请求将如何处理
1./**@HTTP:可以替代其他方法的任意一种
* method 表示请的方法,不区分大小写
* path表示路径
* hasBody表示是否有请求体
*/
@HTTP(method = "get", path = "users/{user}", hasBody = false)
Call<ResponseBody> getFirstBlog(@Path("user") String user);
2./**对baseurl进行替换拼接什么的
* @Url:使用全路径复写baseUrl,适用于非统一baseUrl的场景。
* 值得注意的是@Url需要在所有参数之前:
*/
@GET
Call<ResponseBody> v3(@Url String url);
3./***
*@Streaming 用于下载大文件
*文件下载我们需要使用@Url和 @Streaming ,@Url动态Url正好非常适合我们的场景,
*而使用@Streaming注解可以让我们下载非常大的文件时,避免Retrofit将整个文件读进内存,
*否则可能造成OOM现象。
*/
@Streaming
@GET("news/latest")
Call<ResponseBody> downloadFileWithDynamicUrlAsync(@Url String fileUrl);
4. /***
*@Header 请求头参数
*用于在方法参数里动态添加请求头:
* 动态设置Header值
*/
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
//静态设置Header值
@Headers("Authorization: authorization")//这里authorization就是上面方法里传进来变量的值
@GET("widget/list")
5./***
*@Headers 用于修饰方法,用于设置多个Header值:
*/
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<UserBean> getUser(@Path("username") String username);
6./**
*@Path:URL占位符,用于替换和动态更新,相应的参数必须使用相同的字符串被@Path进行注
*释
*/
@GET("group/{id}/users")
Call<List<UserBean>> groupList(@Path("id") int groupId);
//--> http://baseurl/group/groupId/users
//等同于:
@GET
Call<List<UserBean>> groupListUrl(@Url String url);
7. /**
*@Query,@QueryMap:查询参数,用于GET查询,
*需要注意的是@QueryMap可以约定是否需要encode
*/
@GET("group/users")
Call<List<UserBean>> groupList2(@Query("id") int groupId);
//--> http://baseurl/group/users?id=groupId
//或者
@GET("group/users")
Call<List<UserBean>> getNews(@QueryMap(encoded=true) Map<String, String> options);
8. /**
* 用于Body的JSON格式参数
*@Body:用于POST请求体,将实例对象根据转换方式转换为对应的json字符串参数,
*这个转化方式是GsonConverterFactory定义的。
* 配合@Headers("Accept-Encoding: application/json")使用
*/
@POST("test/sayHi")
@Headers("Accept-Encoding: application/json")
Call<List<UserBean>> addUser(@Body UserBean user);
9./**服务器接受表单参数类型(form-data)时使用
*@Field,@FieldMap:Post方式传递简单的键值对,
*需要添加@FormUrlEncoded表示表单提交
*Content-Type:application/x-www-form-urlencoded
*/
@FormUrlEncoded
@POST("test/sayHello")
Call<ResultBean> postSayHelloByForm(@Field("username") String username, @Field("age") String age);
10. /**
*@Part,@PartMap:用于POST文件上传
*其中@Part MultipartBody.Part代表文件,@Part(“key”) RequestBody代表参数
*需要添加@Multipart表示支持文件上传的表单,Content-Type: multipart/form-data
*/
@Multipart
@POST("upload")
Call<ResponseBody> upload(@Part("description") RequestBody description, @Part MultipartBody.Part file);
搞了这么多我都不知道自己写了些什么
进入正题吧 Retrofit如何使用
大体分为三步吧
1:创建Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
//设置baseUrl,注意baseUrl 应该以/ 结尾。
.baseUrl("http://news-at.zhihu.com/api/4/")//瞎比写得地址
//使用Gson解析器,可以替换其他的解析器
.addConverterFactory(GsonConverterFactory.create())
//设置OKHttpClient,如果不设置会提供一个默认的
.client(new OkHttpClient())
//.client(new UrlConnectionClient())
//.client(new ApacheClient())
// .client(new CustomClient())
.build();
2:创建接口
public interface PubService {
/**@HTTP:可以替代其他方法的任意一种
* method 表示请的方法,不区分大小写
* path表示路径
* hasBody表示是否有请求体
*/
@HTTP(method = "get", path = "users/{user}", hasBody = false)
Call<ResponseBody> getFirstBlog(@Path("user") String user);
/**对baseurl进行替换拼接什么的
* @Url:使用全路径复写baseUrl,适用于非统一baseUrl的场景。
*/
@GET
Call<ResponseBody> v3(@Url String url);
/***
*@Streaming 用于下载大文件
*文件下载我们需要使用@Url和 @Streaming ,@Url动态Url正好非常适合我们的场景,
*而使用@Streaming注解可以让我们下载非常大的文件时,避免Retrofit将整个文件读进内存,
*否则可能造成OOM现象。
*/
@Streaming
@GET
Call<ResponseBody> downloadFileWithDynamicUrlAsync(@Url String fileUrl);
/***
*@Header 请求头参数
*用于在方法参数里动态添加请求头:
* 动态设置Header值
*/
@GET("news/latest")
Call<ResultBean> postSayHi(@Header("city") String city);
/***
*@Headers 用于修饰方法,用于设置多个Header值:
*/
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<UserBean> getUser(@Path("username") String username);
/**
* @Path:URL占位符,用于替换和动态更新,相应的参数必须使用相同的字符串被@Path进行注释
*/
@GET("group/{id}/users")
Call<List<UserBean>> groupList(@Path("id") int groupId);
//--> http://baseurl/group/groupId/users
//等同于:
@GET
Call<List<UserBean>> groupListUrl(@Url String url);
/**
*@Query,@QueryMap:查询参数,用于GET查询,需要注意的是@QueryMap可以约定是否需要encode
*/
@GET("group/users")
Call<List<UserBean>> groupList2(@Query("id") int groupId);
//--> http://baseurl/group/users?id=groupId
//或者
@GET("group/users")
Call<List<UserBean>> getNews(@QueryMap(encoded=true) Map<String, String> options);
/**
* 用于Body的JSON格式参数
*@Body:用于POST请求体,将实例对象根据转换方式转换为对应的json字符串参数,
*这个转化方式是GsonConverterFactory定义的。
* 配合@Headers("Accept-Encoding: application/json")使用
*/
@POST("test/sayHi")
@Headers("Accept-Encoding: application/json")
Call<List<UserBean>> addUser(@Body UserBean user);
/**服务器接受表单参数类型(form-data)时使用
*@Field,@FieldMap:Post方式传递简单的键值对,
*需要添加@FormUrlEncoded表示表单提交
*Content-Type:application/x-www-form-urlencoded
*/
@FormUrlEncoded
@POST("test/sayHello")
Call<ResultBean> postSayHelloByForm(@Field("username") String username, @Field("age") String age);
/**
*@Part,@PartMap:用于POST文件上传
*其中@Part MultipartBody.Part代表文件,@Part(“key”) RequestBody代表参数
*需要添加@Multipart表示支持文件上传的表单,Content-Type: multipart/form-data
*/
@Multipart
@POST("upload")
Call<ResponseBody> upload(@Part("description") RequestBody description, @Part MultipartBody.Part file);
3:异步回调
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://gc.ditu.aliyun.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
QuestService service = retrofit.create(QuestService.class);
final Call<LoginInfo> loginInfo = service.loadInfo();
loginInfo.enqueue(new Callback<LoginInfo>() {
@Override
public void onResponse(Call<LoginInfo> call, Response<LoginInfo> response){
LoginInfo info = respnse.body();
}
@Override
public void onFailure(Call<LoginInfo> call, Throwable t) {
}
});
4.取消请求
loginInfo.cancel();
//Call<StartImageBean> cloneRequsest = startImage.clone();//复制
定义的接口
public interface PService {
@GET("start-image/1080*1776")
Call<StartImageBean> getStartImage();
@GET("start-image/{size}")
Call<StartImageBean> getStartImageByPath(@Path("size") String size);
/**
* sayHello 动态get 参数
*
* @param username
* @param age
* @return
*/
@GET("test/sayHello")
Call<String> sayHello(@Query("username") String username, @Query("age") String age);
@POST
Call<ResultBean> postSayHelloByURL(@Url String url, @Query("username") String username, @Query("age") String age);
@POST("test/sayHi")
@Headers("Accept-Encoding: application/json")
//使用@Headers 可添加header
Call<ResultBean> postSayHi(@Body UserBean userBean);
@Multipart
@POST("test/upload")
Call<ResultBean> upload(@Part("file\"; filename=\"launcher_icon.png") RequestBody file);
//http://localhost:8080/app/res/atom-amd64.deb
@Streaming
@GET
Call<ResponseBody> downloadFileByDynamicUrlAsync(@Url String downloadUrl);
}
//简单使用方法:
1.普通 GET 返回实体对象
private void getStartImage() {
//生成Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
//设置baseUrl,注意baseUrl 应该以/ 结尾。
.baseUrl("http://xxx.com/api/xx/")
//使用Gson解析器,可以替换其他的解析器
.addConverterFactory(GsonConverterFactory.create())
//设置OKHttpClient,如果不设置会提供一个默认的
.client(new OkHttpClient())
.build();
PService messageService = retrofit.create(PService.class);
Call<StartImageBean> startImage = messageService.getStartImage();
startImage.enqueue(new Callback<StartImageBean>() {
@Override
public void onResponse(Call<StartImageBean> call,
Response<StartImageBean> response) {
if (response.isSuccessful()) {
Log.d(TAG, response.body().toString());
resultTextView.setText("" + response.body().toString());
}
}
@Override
public void onFailure(Call<StartImageBean> call, Throwable t) {
resultTextView.setText("" + "error:" + t.getMessage());
}
});
}
2.动态URL GET 返回实体对象
private void getStartImageByPath() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://news-at.zhihu.com/api/4/")
.addConverterFactory(GsonConverterFactory.create())
//设置OKHttpClient,如果不设置会提供一个默认的
//.client(new OkHttpClient())
.build();
PService messageService = retrofit.create(PService.class);
/**
* 可使用以下格式做动态URL参数
* 320*432
480*728
720*1184
1080*1776
*/
Call<StartImageBean>startImage=messageService.getStartImageByPath("320*432");
//异步请求
startImage.enqueue(new Callback<StartImageBean>() {
@Override
public void onResponse(Call<StartImageBean> call, Response<StartImageBean> response) {
if (response.isSuccessful()) {
Log.d(TAG, response.body().toString());
resultTextView.setText("" + response.body().toString());
}
}
@Override
public void onFailure(Call<StartImageBean> call, Throwable t) {
resultTextView.setText("" + "error:" + t.getMessage());
}
});
}
3.GET 动态参数 返回String 返回String类型的json串
private void getSayHello() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
//在build.gradle添加
// compile 'com.squareup.retrofit2:converter-scalars:2.1.0+'
.addConverterFactory(ScalarsConverterFactory.create())
//设置OKHttpClient,如果不设置会提供一个默认的
//.client(new OkHttpClient())
.build();
PService myTestApiService = retrofit.create(PService.class);
Call<String> doubanCall = myTestApiService.sayHello("fuchenxuan", "110");
doubanCall.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
if (response.isSuccessful()) {
Log.d(TAG, response.body().toString());
resultTextView.setText("" + response.body().toString());
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
}
});
}
4.普通 POST 返回实体对象
private void postSayHello() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
//设置OKHttpClient,如果不设置会提供一个默认的
//.client(new OkHttpClient())
.build();
PService myTestApiService = retrofit.create(PService.class);
//Call<ResultBean> doubanCall
= myTestApiService.postSayHello("fuchenxuan", "110");
//Call<ResultBean> doubanCall
= myTestApiService.postSayHelloByForm("fuchenxuan", "110");
//用到了Url注解
Call<ResultBean> doubanCall
= myTestApiService.postSayHelloByURL(API_BASE_URL.concat("test/sayHello"), "fuchenxuan", "110");
doubanCall.enqueue(new Callback<ResultBean>() {
@Override
public void onResponse(Call<ResultBean> call, Response<ResultBean> response) {
if (response.isSuccessful()) {
Log.d(TAG, response.body().toString());
resultTextView.setText("" + response.body().toString());
}
}
@Override
public void onFailure(Call<ResultBean> call, Throwable t) {
}
});
}
5.POST JSON 参数
private void postSayHi() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
//检测接口定义是否正确,适合在开发、测试时使用
.validateEagerly(true)
.addConverterFactory(GsonConverterFactory.create())
//设置OKHttpClient,如果不设置会提供一个默认的
//.client(new OkHttpClient())
//使用RxJava
//.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
PService myTestApiService = retrofit.create(PService.class);
UserBean userBean = new UserBean("fuchenxuan", "1110");
Call<ResultBean> doubanCall = myTestApiService.postSayHi(userBean);
doubanCall.enqueue(new Callback<ResultBean>() {
@Override
public void onResponse(Call<ResultBean> call, Response<ResultBean> response) {
if (response.isSuccessful()) {
//返回原始数据格式
try {
Log.d(TAG, response.raw().body().string());
} catch (IOException e) {
e.printStackTrace();
}
resultTextView.setText("" + response.body().toString());
}
}
@Override
public void onFailure(Call<ResultBean> call, Throwable t) {
}
});
}
6.文件上传
private void upload() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
//设置OKHttpClient,如果不设置会提供一个默认的
//.client(new OkHttpClient())
.build();
PService myTestApiService = retrofit.create(PService.class);
File file = new File(getExternalFilesDir(null), "launcher_icon.png");
RequestBody fileBody
= RequestBody.create(MediaType.parse("image/png"), file);
Call<ResultBean> doubanCall = myTestApiService.upload(fileBody);
doubanCall.enqueue(new Callback<ResultBean>() {
@Override
public void onResponse(Call<ResultBean> call, Response<ResultBean> response) {
if (response.isSuccessful()) {
Log.d(TAG, response.body().toString());
resultTextView.setText("" + response.body().toString());
}
}
@Override
public void onFailure(Call<ResultBean> call, Throwable t) {
// Log.d(TAG, response.body().toString());
resultTextView.setText("" + "error:" + t.getMessage());
}
});
}
7.文件下载
private void downloadFileByDynamicUrlAsync() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
//设置OKHttpClient,如果不设置会提供一个默认的
//.client(new OkHttpClient())
.build();
final PService myTestApiService = retrofit.create(PService.class);
new AsyncTask<Void, Long, Void>() {
@Override
protected Void doInBackground(Void... voids) {
Call<ResponseBody> call
=myTestApiService.downloadFileByDynamicUrlAsync(API_BASE_URL.concat("/res/atom-amd64.deb"));
try {
Response<ResponseBody> response = call.execute();
boolean writtenToDisk = writeResponseBodyToDisk(response.body());
Log.d(TAG, "下载文件 " + writtenToDisk);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
}.execute();
}
8.自定义Converter
9.自定义拦截器Interceptor
10.全局单例的okhttpclient和retrofit
未完待续