在android开发中,网络请求是最常用的操作之一,目前热门的网络请求框架有:Retrofit、volley、okhttp、Android-Async-Http,这里公司项目中用到Retrofit,之前没了解过,这里做个学习记录。
本文参考博文:这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解)
Tag:Retrofit是一个RESTful的Http请求框架的封装,网络请求本质上是okhttp完成,Retrofit仅负责网络请求接口的封装。
请求处理流:
App应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息,之后由 OkHttp 完成后续的请求操作。
步骤共7步:
1.在module的build.gradle中添加对Retrofit库的依赖
dependencies {
compile 'com.squareup.retrofit2:retrofit:2.0.2'
// Retrofit库
}
2.网络权限别忘了
Reception.java
public class Reception {
...
// 根据返回数据的格式和数据解析方式(Json、XML等)定义
// 下面会在实例进行说明
}
Retrofit将网络请求抽象成接口,采用注解描述网络请求参数和配置网络请求参数
- 用 动态代理 动态 将该接口的注解“翻译”成一个 Http 请求,最后再执行 Http 请求
- 注:接口中的每个方法的参数都需要使用注解标注,否则会报错
public interface ApiService {
@FormUrlEncoded
@Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
@POST("{uri}")
Call post(@Path(value = "uri", encoded = true) String uri, @FieldMap Map params);
}
a. @FormUrlEncoded
每个键值对需要用@Filed来注解键名,随后的对象需要提供值。
b. @Multipart
每个键值对需要用@Part来注解键名,随后的对象需要提供值。
public interface GetRequest_Interface {
/**
*表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
* Field("username")
表示将后面的 String name
中name的取值作为 username 的值
*/
@POST("/form")
@FormUrlEncoded
Call testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);
/**
* {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型
* 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息),
*/
@POST("/form")
@Multipart
Call testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);
}
// 具体使用
GetRequest_Interface service = retrofit.create(GetRequest_Interface.class);
// @FormUrlEncoded
Call call1 = service.testFormUrlEncoded1("Carson", 24);
// @Multipart
RequestBody name = RequestBody.create(textType, "Carson");
RequestBody age = RequestBody.create(textType, "24");
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
Call call3 = service.testFileUpload1(name, age, filePart);
a. @Header & @Headers
// @Header
@GET("user")
Call getUser(@Header("Authorization") String authorization)
// @Headers
@Headers("Authorization: authorization")
@GET("user")
Call getUser()
// 以上的效果是一致的。
// 区别在于使用场景和使用方式
// 1. 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头
// 2. 使用方式:@Header作用于方法的参数;@Headers作用于方法
Post
方式 传递 自定义数据类型 给服务器@Field
不过Map要经过
FormBody.Builder
类处理成为符合 Okhttp 格式的表单,如:
FormBody.Builder builder = new FormBody.Builder();
builder.add("key","value");
c. @Field & @FieldMap
@FormUrlEncoded
注解配合使用
d. @Part & @PartMap
作用:发送 Post请求 时提交请求的表单字段
与@Field的区别:功能相同,但携带的参数类型更加丰富,包括数据流,所以适用于 有文件上传 的场景
具体使用:与 @Multipart
注解配合使用
public interface GetRequest_Interface {
/**
* {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型
* 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息),
*/
@POST("/form")
@Multipart
Call testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);
/**
* 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 testFileUpload2(@PartMap Map args, @Part MultipartBody.Part file);
@POST("/form")
@Multipart
Call testFileUpload3(@PartMap Map args);
}
// 具体使用
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"), "这里是模拟文件的内容");
// @Part
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
Call call3 = service.testFileUpload1(name, age, filePart);
ResponseBodyPrinter.printResponseBody(call3);
// @PartMap
// 实现和上面同样的效果
Map fileUpload2Args = new HashMap<>();
fileUpload2Args.put("name", name);
fileUpload2Args.put("age", age);
//这里并不会被当成文件,因为没有文件名(包含在Content-Disposition请求头中),但上面的 filePart 有
//fileUpload2Args.put("file", file);
Call call4 = service.testFileUpload2(fileUpload2Args, filePart); //单独处理文件
ResponseBodyPrinter.printResponseBody(call4);
}
e. @Query和@QueryMap
作用:用于 @GET
方法的查询参数(Query = Url 中 ‘?’ 后面的 key-value)
如:url = http://www.println.net/?cate=android,其中,Query = cate
具体使用:配置时只需要在接口方法中增加一个参数即可:
@GET("/")
Call cate(@Query("cate") String cate);
}
// 其使用方式同 @Field与@FieldMap,这里不作过多描述
f. @Path
public interface GetRequest_Interface {
@GET("users/{user}/repos")
Call getBlog(@Path("user") String user );
// 访问的API是:https://api.github.com/users/{user}/repos
// 在发起请求时, {user} 会被替换为方法的第一个参数 user(被@Path注解作用)
}
g. @Url
public interface GetRequest_Interface {
@GET
Call testUrlAndQuery(@Url String url, @Query("showAll") boolean showAll);
// 当有URL注解时,@GET传入的URL就可以省略
// 当GET、POST...HTTP等方法中没有设置Url时,则必须使用 {@link Url}提供
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/") // 设置网络请求的Url地址
.addConverterFactory(GsonConverterFactory.create()) // 设置数据解析器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 支持RxJava平台
.build();
URL说明:
Retrofit把 网络请求的URL 分成了两部分设置:
- 网络请求的完整 Url =在创建Retrofit实例时通过.baseUrl()设置 +网络请求接口的注解设置(
@POST("{uri}") Callpost(@Path(value = "uri", encoded = true) String uri, @FieldMap Map params); )
数据解析器 | 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 |
使用时如使用的是
Android
默认的CallAdapter
,则不需要添加网络请求适配器的依赖,否则则需要按照需求进行添加
Retrofit 提供的CallAdapter
网络请求适配器 | 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 |
// 创建 网络请求接口 的实例
ApiService apiService= retrofit.create(ApiService.class);
//对 发送请求 进行封装
Call call = apiService.post("appApi",param);
//发送网络请求(异步)
call.enqueue(new Callback() {
//请求成功时回调
@Override
public void onResponse(Call call, Response response) {
//请求处理,输出结果
response.body().show();
}
//请求失败时候的回调
@Override
public void onFailure(Call call, Throwable throwable) {
System.out.println("连接失败");
}
});
// 发送网络请求(同步)
Response response = call.execute();
通过response
类的 body()
对返回的数据进行处理
//发送网络请求(异步)
call.enqueue(new Callback() {
//请求成功时回调
@Override
public void onResponse(Call call, Response response) {
// 对返回数据进行处理
//Translation translation= response.body();
response.body().show();
}
//请求失败时候的回调
@Override
public void onFailure(Call call, Throwable throwable) {
System.out.println("连接失败");
}
});
// 发送网络请求(同步)
Response response = call.execute();
// 对返回数据进行处理
response.body().show();
Retrofit总体使用步骤就是以上七步。
同时Retrofit可以配合RxJava使用,这里继续学习RxJava。