1 开始使用
- https://github.com/square/retrofit
//retrofit:2.3.0 里面引用了 okhttp:3.8.0
compile 'com.squareup.retrofit2:retrofit:2.3.0'
//converter-gson:2.3.0 里面引用了 gson:2.7.0
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
Retrofit 是遵循 RESTful API 规则的网络请求的封装,底层就是OkHttp
请求封装为interface,并通过“注解”来声明api的相关信息
- 其中一种普通 API 设计规则
xxx.com/api/createUser
xxx.com/api/getUser
xxx.com/api/updateUser
xxx.com/api/deleteUser
- RESTful API 设计规则
RESTful的核心思想做一个最简练的总结,那就是:所谓”资源”,就是网络上的一个实体,或者说是网络上的一个具体信息。那么我们访问API的本质就是与网络上的某个资源进行互动而已。那么,因为我们实质是访问资源,所以RESTful设计思想的提出者Fielding认为:
URI当中不应当出现动词,因为”资源“表示一种实体,所以应该用名词表示,而动词则应该放在HTTP协议当中。
[POST]xxx.com/api/User
[GET] xxx.com/api/User
[PUT]xxx.com/api/User
[DELETE]xxx.com/api/User
序号 | 注解 | 用途 |
---|---|---|
qq1 | @POST | post 请求 |
qq2 | @DELETE | delete 请求 |
qq3 | @PUT | put 请求 |
qq4 | @GET | get 请求 |
qq5 | @PATCH | patch请求,该请求是对put请求的补充,用于更新局部资源 |
qq6 | @HEAD | head请求 |
qq7 | @OPTIONS | option请求 |
qq8 | @HTTP | http 请求 可以设置达到上面任意请求 |
cs1 | @Url | 指定 |
cs2 | @Path | url 替换 |
cs3 | @Query | 查询字符串 |
cs4 | @QueryMap | 比较多的查询字符串集合 |
cs5 | @Field | 表单参数 |
cs6 | @FieldMap | 表单参数集合 |
cs7 | @Headers | 为方法添加请求响应头 |
cs8 | @Header | 为方法参数添加请求响应头 |
cs9 | @Part | 与Multipart注解结合使用,适合文件上传 |
cs10 | @PartMap | 默认接受的类型是Map |
cs11 | @Body | 请求上传的对象,发送非表单数据,如 传递json格式数据 |
bj1 | @FormUrlEncoded | Form表单数据,每个键值对需要使用@Field注解 |
bj2 | @Multipart | 发送multipart数据,需要配合使用@Part @PartMap |
bj3 | @Streaming | 响应用字节流的形式返回.多用于下载大文件 |
- step1 创建 接口,加入一个方法
public interface GitHubService {
@GET("/")
Call listGitHubApis();
}
- step2 创建 一个Retrofit
String url = "https://api.github.com/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)//url必须以‘/’结尾
.addConverterFactory(GsonConverterFactory.create())
.build();
- step3 执行请求
//retrofit.create来生成一个接口实现类
GitHubService gitHubService=retrofit.create(GitHubService.class);
//调用指定方法
Call gitHubBeanCall=gitHubService.listGitHubApis();
//执行请求
gitHubBeanCall.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
String authorizations_url= response.body().getAuthorizations_url();
String team_url= response.body().getTeam_url();
}
@Override
public void onFailure(Call call, Throwable t) {
Log.i("zfq", t.getMessage());
}
});
请求注解
qq1 @POST 增
- 意味 增
@POST("api/users")
Call newUser(@Body UserBean user);
Call call = gitHubService.newUser(new UserBean("tsr","male",24));
qq2 @DELETE 删
- 意味 删
@DELETE("api/users/{id}")
Call deleteUser(@Path("id") String userid);
Call call = gitHubService.deleteUser("24");
qq3 @PUT 改
- 意味 改
@PUT("api/users/{id}")
Call updateUser(@Path("id") String userid);
Call call = gitHubService.updateUser("24");
qq4 @GET 查
- 意味 查
@GET("/")
Call listGitHubApis();
Call gitHubBeanCall=gitHubService.listGitHubApis();
qq5 @PATCH
- patch请求,该请求是对put请求的补充,用于更新局部资源
- 暂略
qq6 @HEAD
- head 请求
- 暂略
qq7 @OPTIONS
- options 请求
- 暂略
qq8 @HTTP
- HTTP注解则可以代替以上方法中的任意一个注解
/**
* method 表示请求的方法,区分大小写
* path表示路径
* hasBody表示是否有请求体
*/
@HTTP(method = "GET", path = "blog/{id}", hasBody = false)
Call getBlog(@Path("id") int id);
参数注解
cs1 @Url 指定url
- 使用动态的请求的网址,会复写之前的baseUrl,值得注意的是@Url需要在所有参数之前
@POST
Call postSayHelloByURL(@Url String url,@Query("username") String username, @Query("age") String age);
cs2 @Path url中值替换
- 适合用于RESTful api
- @Path 路径中需要替换{}的情况,{}内要和@Path("")内对应一致
@GET("users/{user}")
Call listUser(@Path("user") String user);
Call userBeanCall=gitHubService.listUser("louisgeek");
cs3 @Query 查询字符串
- https://api.github.com/search/users?q=okhttp
- 查询参数 @Query("")内需要和url里对应的参数一致
旧的方式依旧可行 毋庸置疑的 【查询 “okhttp”】
@GET("/search/users?q=okhttp")
Call searchUser();
Call searchResultBeanCall=gitHubService.searchUser();
@Query 方式 【查询 “activity”】
@GET("/search/users")
Call searchUsers(@Query("q") String search);
Call searchResultBeanCall2=gitHubService.searchUsers("activity");
cs4 @QueryMap 查询字符串组
- 查询集合 即多个参数组成的Map数组
@GET("/search/users")
Call searchUsers(@QueryMap Map params);
Map params =new HashMap<>();
params.put("param1","value1");
params.put("param2","value2");
Call call = gitHubService.searchUsers(params);
cs5 @Field 表单参数
- 需要和@FormUrlEncoded配合使用
@FormUrlEncoded
@POST("themelist/essenceAsk")
Call getFirstBlog(@Field("page") String PAGE,@field("pageSize") String String);
}
cs6 @FieldMap 表单参数组
- 需要和@FormUrlEncoded配合使用
@FormUrlEncoded
@POST("/url")
Call postForm(@FieldMap Map maps);
cs7 @Headers 为方法添加请求响应头
@Headers("Content-type:application/x-www-form-urlencoded;charset=UTF-8")
@FormUrlEncoded
@POST("api/users")
Call uploadNewUser(@Field("username") String username,@Field("gender") String male);
cs8 @Header 为方法参数添加请求响应头
@FormUrlEncoded
@POST("api/users")
Call uploadNewUser(@Header("Content-Type") String contentType,@Field("username") String username,@Field("gender") String male,@Field("age") int age);
}
// 调用
Call call = service.uploadNewUser("application/x-www-form-urlencoded;charset=UTF-8","张德帅","male",24);
cs9 @Part
- 用于上传文件,与@MultiPart注解结合使用
@Multipart
@POST("/url")
Call uploadFlie(
@Part("description") RequestBody description,
@Part("files") MultipartBody.Part file);
cs10 @PartMap
- 用于上传文件,与@MultiPart注解结合使用,默认接受的类型是Map
,可用于实现多文件上传
@Multipart
@POST("{url}")
Call uploadFiles(
@Path("url") String url,
@PartMap() Map maps);
cs11 @Body
- 非表单数据,比如想要以post方式传递json格式数据
- 被@Body注解的的UserBean将会被Gson转换成RequestBody发送到服务器
@POST("api/users")
Call uploadNewUser(@Body UserBean user);
Call call = gitHubService.uploadNewUser(new UserBean("tsr","male",24));
标记注解
bj1 @FormUrlEncoded
- 以form表单方式上传
- @Field
- @FieldMap 使用类似@QueryMap
@FormUrlEncoded
@POST("api/users")
Call uploadNewUser(@Field("username") String username, @Field("gender") String male, @Field("age") int age);
@FormUrlEncoded
@POST("api/users")
Call uploadNewUser(@FieldMap Map fields);
bj2 @Multipart
- 表示请求发送multipart数据,需要配合使用@Part @PartMap
@Multipart
@POST("/url")
Call uploadFlie(
@Part("description") RequestBody description,
@Part("files") MultipartBody.Part file);
@Multipart
@POST("test/upload")
Call upload(@Part("file\"; filename=\"launcher_icon.png") RequestBody file);
File file = new File(getExternalFilesDir(null), "launcher_icon.png");
RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), file);
Call doubanCall = myTestApiService.upload(fileBody);
doubanCall.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
if (response.isSuccessful()) {
Log.d(TAG, response.body().toString());
resultTextView.setText("" + response.body().toString());
}
}
@Override
public void onFailure(Call call, Throwable t) {
// Log.d(TAG, response.body().toString());
resultTextView.setText("" + "error:" + t.getMessage());
}
});
public interface FileUploadService {
@Multipart
@POST("upload")
Call upload(@Part("description") RequestBody description,
@Part MultipartBody.Part file);
}
// 创建 RequestBody,用于封装构建RequestBody
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), file);
// MultipartBody.Part 和后端约定好Key,这里的partName是用image
MultipartBody.Part body =
MultipartBody.Part.createFormData("image", file.getName(), requestFile);
// 添加描述
String descriptionString = "hello, 这是文件描述";
RequestBody description =
RequestBody.create(
MediaType.parse("multipart/form-data"), descriptionString);
// 执行请求
Call call = service.upload(description, body);
call.enqueue(new Callback() {
@Override
public void onResponse(Call call,
Response response) {
Log.v("Upload", "success");
}
@Override
public void onFailure(Call call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
}
@POST()
Call upLoad(
@Url() String url,
@Body RequestBody Body);
//构建body
RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("name", name)
.addFormDataPart("name", psd)
.addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/*"), file))
.build();
Call call = service.upload(url, requestBody );
// 执行
call.enqueue(new Callback() {
@Override
public void onResponse(Call call,
Response response) {
Log.v("Upload", "success");
}
@Override
public void onFailure(Call call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
bj3 @Streaming
- 表示响应用字节流的形式返回.如果没使用该注解,默认会把数据全部载入到内存中.该注解在在下载大文件的特别有用
@Streaming
@GET
Call downloadFileByDynamicUrlAsync(@Url String downloadUrl);
new Thread(new Runnable() {
@Override
public void run() {
Call call = myTestApiService.downloadFileByDynamicUrlAsync(API_BASE_URL.concat("/res/atom-amd64.deb"));
try {
Response response = call.execute();
boolean writtenToDisk = writeResponseBodyToDisk(response.body());
Log.d(TAG, "下载文件 " + writtenToDisk);
} catch (IOException e) {
e.printStackTrace();
}
//
}
}).start();
……
//写入到磁盘根目录
private boolean writeResponseBodyToDisk(ResponseBody body) {
try {
File futureStudioIconFile = new File(Environment.getExternalStorageDirectory() + File.separator + "atom.deb");
InputStream inputStream = null;
OutputStream outputStream = null;
try {
byte[] fileReader = new byte[4096];
final long fileSize = body.contentLength();
long fileSizeDownloaded = 0;
inputStream = body.byteStream();
outputStream = new FileOutputStream(futureStudioIconFile);
while (true) {
int read = inputStream.read(fileReader);
if (read == -1) {
break;
}
outputStream.write(fileReader, 0, read);
fileSizeDownloaded += read;
Log.d(TAG, "file download: " + fileSizeDownloaded + " of " + fileSize);
final long finalFileSizeDownloaded = fileSizeDownloaded;
runOnUiThread(new Runnable() {
@Override
public void run() {
resultTextView.setText("file download: " + finalFileSizeDownloaded + " of " + fileSize);
}
});
}
outputStream.flush();
return true;
} catch (IOException e) {
return false;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
} catch (IOException e) {
return false;
}
}
参考文章
- 你真的会用Retrofit2吗?Retrofit2完全教程 http://www.jianshu.com/p/308f3c54abdd
- Android网络请求库 - Say hello to retrofit http://blog.csdn.net/ghost_programmer/article/details/52372065
- Retrofit 2.0 超能实践(一),完美支持加密Https传输 http://www.jianshu.com/p/16994e49e2f6
- Retrofit 2.0:有史以来最大的改进 http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0915/3460.html
- Retrofit2 简明教程(一)http://blog.csdn.net/vfush/article/details/51735965
- Android 手把手教你使用Retrofit2 http://www.jianshu.com/p/73216939806a
- Retrofit2 学习总结 http://www.jianshu.com/p/a8b88c7fe831
- 好用的网络请求库Retrofit2(入门及讲解) http://blog.csdn.net/biezhihua/article/details/49232289
- Retrofit2 完全解析 探索与okhttp之间的关系 http://blog.csdn.net/lmj623565791/article/details/51304204
- Retrofit2.0使用详解 http://blog.csdn.net/ljd2038/article/details/51046512
- RxJava 与 Retrofit 结合的最佳实践 http://gank.io/post/56e80c2c677659311bed9841