Android之网络请求9————Retrofit的简单使用
Android之网络请求8————Retrofit的简单使用
文章目录
- Android之网络请求8————Retrofit的简单使用
- 一.Retrofit的介绍
- 二.Retrofit的简单使用
- 三.Retrofit的注解
- 1.概述
- 2.网络请求方法
- 3.标记类
- 4.网络请求参数
- 四.Retrofit的数据解析器和网络请求适配器
- 1.数据解析器
- 2.网络请求适配器
- 五.Retrofit和GSON
- 1.步骤a:添加Retrofit库的依赖
- 2.步骤b:创建 接收服务器返回数据 的类
- 3.步骤c:创建 用于描述网络请求 的接口
- 4.步骤d:进行网络请求
- 5.运行结果
- 六.Retrofit和Rxjava的结合
- 1.步骤a:添加Retrofit库的依赖
- 2.步骤b:创建 接收服务器返回数据 的类
- 3.步骤c:创建 用于描述网络请求 的接口
- 4.步骤d:进行网络请求
- 5.运行结果
- 七.参考资料
- 八.文章索引
一.Retrofit的介绍
Retreofit是什么,根据其官方文档的介绍,他就是一个适用于 Android 和 Java 的类型安全的 HTTP 客户端。特别说明Retrofit网络请求本质是有OkHttp完成的,而Retrofit仅负责网络请求接口的封装。
二.Retrofit的简单使用
Retrofit的简单使用我们先从请求百度URL开始
步骤1:
添加第三方库依赖
compile 'com.squareup.retrofit2:retrofit:2.4.0' compile 'com.squareup.retrofit2:converter-scalars:2.3.0'
步骤2:
添加权限
<uses-permission android:name="android.permission.INTERNET"/>
步骤3:
创建用于描述请求的接口
public interface BaiduInterface { //@GET指定请求方法, @GET Call<String> baidu(@Url String url);}
步骤4:
进行请求
//a.创建Retrofit对象 Retrofit retrofit = new Retrofit.Builder() //指定baseurl,这里有坑,最后后缀出带着“/” .baseUrl("http://www.baidu.com/") //设置内容格式,这种对应的数据返回值是String类型 .addConverterFactory(ScalarsConverterFactory.create()) //定义client类型 .client(new OkHttpClient()) //创建 .build(); //b,获得定义的接口的实例 BaiduInterface baiduInterface = retrofit.create(BaiduInterface.class); //配置参数 Call<String> baidu = baiduInterface.baidu("http://www.baidu.com"); //c.执行异步请求 baidu.enqueue(new Callback<String>() { @Override public void onResponse(Call<String> call, Response<String> response) { Log.d("1111", "onResponse: "+response.body()); } @Override public void onFailure(Call<String> call, Throwable t) { Log.d("1111", "onResponse: "+t); } });
请求结果:
三.Retrofit的注解
上面我们简单使用了Retrofit请求了百度的。对Retrofit的使用有了简单的了解,在上面的代码中,出现了@GET和@URL,可以看出Retrofit大量使用了注解,对请求进行了封装,我们继续来看Retrofit中使用的注解。
1.概述
在Retrofit中,注解的使用都在定义的接口中,分为3类:即网络请求方法,标记类,网络请求参数。
2.网络请求方法
网络请求方法如下:
可以看出来这些都是Http的方法,我们一般常用的就是GET和POST
具体说明:
a. @GET、@POST、@PUT、@DELETE、@HEAD
以上方法分别对应 HTTP中的网络请求方式
每个注解后面都可以设置一个URL,也可以不设置
public interface RetrofitInterface { @GET("https://www.baidu.com") Call<String> baidu(); //@GE作用:采用Get方法发送请求 //Call String是请求返回数据的格式,可以是String,也可以是json,也可是GSON。 //baidu() 即进行请求的方法 //关于URL部分,在下面有教详细的讲解}
[email protected]
作用:替换@GET、@POST、@PUT、@DELETE、@HEAD注解的作用 及 更多功能拓展
具体使用:通过属性method、path、hasBody进行设置
public interface RetrofitInterface { /** * method:网络请求的方法(区分大小写) * path:网络请求地址路径 * hasBody:是否有请求体 */ @HTTP(method = "GET", path ="https://www.baidu.com", hasBody = false) Call<ResponseBody> getCall(@Path("id") int id); // method 的值 retrofit 不会做处理,所以要自行保证准确}
c.关于URL
Retrofit将URL分为两部分,一部分在请求接口的注解后,一部分在Retrofit的baseUrl中。即
// 第1部分:在网络请求接口的注解设置 @GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")Call<Translation> getCall();// 第2部分:在创建Retrofit实例时通过.baseUrl()设置Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://fanyi.youdao.com/") //设置网络请求的Url地址 .addConverterFactory(GsonConverterFactory.create()) //设置数据解析器 .build();
网络请求的完整 Url =在创建Retrofit实例时通过.baseUrl()设置 +网络请求接口的注解设置(下面称 “path“ )
具体整合规则
path的URL还可以使用替换块
@GET("group/{id}/users")Call<List<User>> groupList(@Path("id") int groupId);
同时网络请求参数@URL也可以设置URL
public interface RetrofitInterface { @GET Call<String> baidu(@Url String url);}
3.标记类
a.FormUrlEncoded
- 作用:表示发送form-encoded的数据
- 注意:每个键值对都需要用@Filed来注解键名,随后的对象需要提供值。
定义接口方法
public interface RetrofitInterface { /** *表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded) * Field("username")
表示将后面的 String name
中name的取值作为 username 的值 */ @POST("/form") @FormUrlEncoded Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);}
b.Multipart
- 作用:表示发送form-encoded的数据(适用于 有文件 上传的场景)
- 注意:每个键值对都需要用@part来注解键名,随后对象需要提供值
public interface RetrofitInterface { /** * {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型 * 除 {@link okhttp3.MultipartBody.Part} 以外, * 其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息), */ @POST("/form") @Multipart Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);}
[email protected]
- 作用:表示返回的数据以流的形式返回,场用于大文件传输的场景
- 注意:url由于是可变的,因此用 @URL 注解符号来进行指定,大文件官方建议用 @Streaming 来进行注解,不然会出现IO异常,小文件可以忽略不注入。如果想进行断点续传的话 可以在此加入header
public interface ApiService { @Streaming @GET Observable<ResponseBody> downloadFile(@Url String fileUrl);}
4.网络请求参数
[email protected] & @Headers
- 作用:添加请求头
具体使用:
// @Header@GET("user")Call<User> getUser(@Header("Authorization") String authorization)// @Headers@Headers("Authorization: authorization")@GET("user")Call<User> getUser()// 以上的效果是一致的。// 区别在于使用场景和使用方式// 1. 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头// 2. 使用方式:@Header作用于方法的参数;@Headers作用于方法
[email protected]
- 作用:以Post方式传递自定义数据类型给服务器
- 注意: 如果提交的是一个Map,那么作用相当于@Field,不过Map要经过FormBody.Builder 类处理成为符合 Okhttp 格式的表单,如:
FormBody.Builder builder = new FormBody.Builder();builder.add("key","value");
c.Field&FieldMap
- 作用:发送 Post请求 时提交请求的表单字段
- 注意:与 @FormUrlEncoded 注解配合使用
Field的使用
public interface RetrofitInterface { /** *表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded) * Field("username")
表示将后面的 String name
中name的取值作为 username 的值 */ @POST("/form") @FormUrlEncoded Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);}//具体使用 Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);
FieldMap的使用
public interface RetrofitInterface { /** *表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded) * Field("username")
表示将后面的 String name
中name的取值作为 username 的值 */ @POST("/form") @FormUrlEncoded Call<ResponseBody>testFormUrlEncoded2(@FieldMap Map<String, Object> map);}//具体使用 Map<String, Object> map = new HashMap<>(); map.put("username", "Carson"); map.put("age", 24); Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);
[email protected] & @PartMap
- 作用:发送的Post请求时提交的表单字段
- 注意:与 @Multipart 注解配合使用
- 与@Field的区别:功能相同,但携带的参数类型更加丰富,包括数据流,所以适用于 有文件上传 的场景
@Part的使用
public interface RetrofitInterface { /** * {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型 * 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息), */ @POST("/form") @Multipart Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);} MediaType textType = MediaType.parse("text/plain"); RequestBody name = RequestBody.create(textType, "Carson"); RequestBody age = RequestBody.create(textType, "24"); RequestBody file = RequestBody.create(MediaType.parse("application/octet-stream"), "这里是模拟文件的内容");//调用 MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file); Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart); ResponseBodyPrinter.printResponseBody(call3);
@PartMap的使用
public interface RetrofitInterface { /** * PartMap 注解支持一个Map作为参数,支持 {@link RequestBody } 类型, * 如果有其它的类型,会被{@link retrofit2.Converter}转换,如后面会介绍的 使用{@link com.google.gson.Gson} 的 {@link retrofit2.converter.gson.GsonRequestBodyConverter} * 所以{@link MultipartBody.Part} 就不适用了,所以文件只能用 @Part MultipartBody.Part */ @POST("/form") @Multipart Call<ResponseBody> testFileUpload2(@PartMap Map<String, RequestBody> args, @Part MultipartBody.Part file);} MediaType textType = MediaType.parse("text/plain"); RequestBody name = RequestBody.create(textType, "Carson"); RequestBody age = RequestBody.create(textType, "24"); RequestBody file = RequestBody.create(MediaType.parse("application/octet-stream"), "这里是模拟文件的内容");//调用 Map<String, RequestBody> fileUpload2Args = new HashMap<>(); fileUpload2Args.put("name", name); fileUpload2Args.put("age", age); //这里并不会被当成文件,因为没有文件名(包含在Content-Disposition请求头中),但上面的 filePart 有 //fileUpload2Args.put("file", file); Call<ResponseBody> call4 = service.testFileUpload2(fileUpload2Args, filePart); //单独处理文件 ResponseBodyPrinter.printResponseBody(call4);
[email protected]和@QueryMap
- 作用:用于 @GET 方法的查询参数(Query = Url 中 ‘?’ 后面的 key-value)
- 使用:和上面的两个相同
f. @Path
- 作用:URL的省缺值
@GET("group/{id}/users")Call<List<User>> groupList(@Path("id") int groupId);
[email protected]
- 作用:直接传入一个请求的URL变量
- 具体使用
public interface RetrofitInterface { @GET Call<String> baidu(@Url String url);}
四.Retrofit的数据解析器和网络请求适配器
在上面的请求百度的例子中,我们使用了ScalarsConverterFactory.create()作为数据的解析器,同时Retrofit也支持多种网络请求适配器方式,比如:guava、Java8和rxjava
数据解析器和网络请求的适配器的添加发生在创建 Retrofit 实例
Retrofit retrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) // 设置数据解析器 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 支持RxJava平台 .build();
1.数据解析器
Retrofit支持多种数据解析器,如下:
数据解析器 | Gradle依赖 |
---|---|
Gson | com.squareup.retrofit2:converter-gson:2.0.2 |
Jackson | com.squareup.retrofit2:converter-jackson:2.0.2 |
Simple XML | com.squareup.retrofit2:converter-simplexml:2.0.2 |
Protobuf | com.squareup.retrofit2:converter-protobuf:2.0.2 |
Moshi | com.squareup.retrofit2:converter-moshi:2.0.2 |
Wire | com.squareup.retrofit2:converter-wire:2.0.2 |
Scalars | com.squareup.retrofit2:converter-scalars:2.0.2 |
2.网络请求适配器
Retrofit支持多种网络请求适配器方式:guava、Java8和rxjava.
使用时如使用的是 Android 默认的 CallAdapter,则不需要添加网络请求适配器的依赖
需要在Gradle添加依赖:
网络请求适配器 | Gradle依赖 |
---|---|
guava | com.squareup.retrofit2:adapter-guava:2.0.2 |
Java8 | com.squareup.retrofit2:adapter-java8:2.0.2 |
rxjava | com.squareup.retrofit2:adapter-rxjava:2.0.2 |
五.Retrofit和GSON
以豆瓣电影上映接口的请求为例:
API接口
请求URL:
返回的JSON数据(详细内容可查看链接):
具体实现:
1.步骤a:添加Retrofit库的依赖
添加Retrofit和GSON的依赖
compile 'com.squareup.retrofit2:retrofit:2.4.0' compile 'com.squareup.retrofit2:converter-gson:2.4.0'
添加权限
<uses-permission android:name="android.permission.INTERNET"/>
2.步骤b:创建 接收服务器返回数据 的类
这里只接收了部分数据
public class Theaters { private int count; //返回数量 private int start; //分页量 private int total; //数据库总数量 @SerializedName("subjects") private List<Subjects> data; //电影的具体信息 private class Subjects { private String title;//电影名 private String mainland_pubdate;//大陆上映时间 private String alt;//网页连接 } //定义 输出返回数据 的方法 public void show() { Log.d("返回数量", ""+count); Log.d("分页量", ""+start); Log.d("数据库总数量", ""+total); for (Subjects subjects: data){ Log.d("电影名", ""+subjects.title); Log.d("大陆上映时间", ""+subjects.mainland_pubdate); Log.d("网页连接", ""+subjects.alt); } }}
3.步骤c:创建 用于描述网络请求 的接口
public interface RetrofitInterface { @GET("in_theaters") Call<Theaters> theaters(@QueryMap Map<String ,Object>map);}
4.步骤d:进行网络请求
//a.创建Retrofit对象 Retrofit retrofit = new Retrofit.Builder() //指定baseurl,这里有坑,最后后缀出带着“/” .baseUrl("https://api.douban.com/v2/movie/") //设置内容格式,这种对应的数据返回值是String类型 .addConverterFactory(GsonConverterFactory.create()) //创建 .build(); //b,获得定义的接口的实例 RetrofitInterface retrofitInterface = retrofit.create(RetrofitInterface.class); // 实现的效果与上面相同,但要传入Map Map<String, Object> map = new HashMap<>(); map.put("apikey", "0b2bdeda43b5688921839c8ecb20399b"); map.put("start",0); map.put("count", 100); //配置参数 Call<Theaters> call = retrofitInterface.theaters(map); //c.进行网络请求 call.enqueue(new Callback<Theaters>() { //请求成功时回调 @Override public void onResponse(Call<Theaters> call, Response<Theaters> response) { // 处理返回的数据结果 response.body().show(); } //请求失败时回调 @Override public void onFailure(Call<Theaters> call, Throwable throwable) { Log.e("retrofit", "onFailure: "+throwable); } });
5.运行结果
六.Retrofit和Rxjava的结合
还是以上面的接口为例:关于Rxjava更多详细的内容可以参看我之前的博客Android之Rxjava2.X 1————Rxjava概述
API接口同上
1.步骤a:添加Retrofit库的依赖
添加Retrofit和GSON的依赖
// Android 支持 Rxjava // 此处一定要注意使用RxJava2的版本 compile 'io.reactivex.rxjava2:rxjava:2.1.7' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' // Android 支持 Retrofit compile 'com.squareup.retrofit2:retrofit:2.4.0' // 衔接 Retrofit & RxJava // 此处一定要注意使用RxJava2的版本 compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' // 支持Gson解析 compile 'com.squareup.retrofit2:converter-gson:2.4.0'
添加权限
<uses-permission android:name="android.permission.INTERNET"/>
2.步骤b:创建 接收服务器返回数据 的类
这里只接收了部分数据
public class Theaters { private int count; //返回数量 private int start; //分页量 private int total; //数据库总数量 @SerializedName("subjects") private List<Subjects> data; //电影的具体信息 private class Subjects { private String title;//电影名 private String mainland_pubdate;//大陆上映时间 private String alt;//网页连接 } //定义 输出返回数据 的方法 public void show() { Log.d("返回数量", ""+count); Log.d("分页量", ""+start); Log.d("数据库总数量", ""+total); for (Subjects subjects: data){ Log.d("电影名", ""+subjects.title); Log.d("大陆上映时间", ""+subjects.mainland_pubdate); Log.d("网页连接", ""+subjects.alt); } }}
3.步骤c:创建 用于描述网络请求 的接口
public interface RetrofitInterface { @GET("in_theaters") Observable<Theaters> theaters2(@QueryMap Map<String ,Object>map);}
4.步骤d:进行网络请求
//a.创建Retrofit对象 Retrofit retrofit = new Retrofit.Builder() //指定baseurl,这里有坑,最后后缀出带着“/” .baseUrl("https://api.douban.com/v2/movie/") //设置内容格式,这种对应的数据返回值是String类型 .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 支持RxJava //创建 .build(); //b,获得定义的接口的实例 RetrofitInterface retrofitInterface = retrofit.create(RetrofitInterface.class); // 实现的效果与上面相同,但要传入Map Map<String, Object> map = new HashMap<>(); map.put("apikey", "0b2bdeda43b5688921839c8ecb20399b"); map.put("start", 0); map.put("count", 100); //配置参数 Observable<Theaters> observable = retrofitInterface.theaters2(map); //c. 通过Rxjava进行网络请求 observable.subscribeOn(Schedulers.io()) // 切换到IO线程进行网络请求 .observeOn(AndroidSchedulers.mainThread()) // 切换回到主线程 处理请求结果 .subscribe(new Observer<Theaters>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(Theaters result) { // e.接收服务器返回的数据 result.show(); } @Override public void onError(Throwable e) { Log.d("Retrofit", "请求失败"); } @Override public void onComplete() { } });
5.运行结果
https://www.jianshu.com/p/0fda3132cf98
七.参考资料
这是一份很详细的 Retrofit 2.0 使用教程
网络加载框架 - Retrofit
Retrofit 官方文档翻译
八.文章索引
Android之网络请求1————HTTP协议
Android之网络请求2————OkHttp的基本使用
Android之网络请求3————OkHttp的拦截器和封装
Android之网络请求4————OkHttp源码1:框架
Android之网络请求5————OkHttp源码2:发送请求
Android之网络请求6————OkHttp源码3:拦截器链
Android之网络请求7————OkHttp源码4:网络操作
Android之网络请求8————OkHttp源码5:缓存相关
Android之网络请求9————Retrofit的简单使用
Android之网络请求10————Retrofit的进阶使用
Android之网络请求11————Retrofit的源码分析
更多相关文章
- Android中数据存储——文件存储数据
- 在android中使用Post方式提交数据
- android 网络交互
- 深入探究Android的WebView下载网络文件的盗链问题
- Android与服务器端数据交互
- Android 数据库批量查询数据的操作
- Android中ListView分页加载数据