Android 网络框架:Retrofit2注解篇
前言
Retrofit有24个注解,其中12个方法注解,12个参数注解。
12个方法注解可有细分为以下几种:
① 8个HTTP请求注解
② 3个标记注解
③ 1个请求头注解
HTTP请求注解(共8个)
名称 | 说明 |
---|---|
GET | 对应HTTP中的GET请求 |
POST | POST请求 |
PUT | PUT请求 |
DELETE | DELETE请求 |
PATCH | PATCH请求 |
HEAD | HEAD请求 |
OPTIONS | OPTIONS请求 |
HTTP | 用于替代以上方法,自定义HTTP请求 |
使用@GET举个例子,代码如下所示:
interface WordService {
@GET("query")
fun getWord(@Query("word") word: String, @Query("dtype") dtype: String,@Query("key") key: String): Observable<WordData>
}
使用@HTTP举个例子,代码如下所示:
interface WordService {
@HTTP(method = "GET",path = "query",hasBody = false)
fun getWord(@Query("word") word: String, @Query("dtype") dtype: String,@Query("key") key: String): Observable<WordData>
}
标记注解(共3个)
名称 | 说明 |
---|---|
FormUrlEncoded | 请求体是From表单 |
Multipart | 请求体是流 |
Streaming | 直接返回值,不写入内存 |
FormUrlEncoded
Field或FieldMap提交数据,不使用FormUrlEncoded会报错,如下所示:
java.lang.IllegalArgumentException: @Field parameters can only be used with form encoding. (parameter #1)
java.lang.IllegalArgumentException: @FieldMap parameters can only be used with form encoding. (parameter #1)
使用了之后会改变编码格式为:“Content-Type: application/x-www-form-urlencoded”
正确的代码示例如下所示:
@FormUrlEncoded
@POST("query")
fun getWord(@Field("word") word: String, @Field("dtype") dtype: String, @Field("key") key: String): Observable<WordData>
Multipart
上传文件需要使用到Multipart,使用之后会将编码格式改为:“Content-Type: multipart/form-data”
@Multipart
@POST("query")
fun getWord(@PartMap params: Map<String, String>): Observable<ResponseBody>
示例代码如下所示:
var retrofit = Retrofit.Builder()
.baseUrl("http://v.juhe.cn/xhzd/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.build()
var wordService = retrofit.create(WordService::class.java)
var map = mapOf("word" to "你","json" to "", "key" to "c5c6a09be5cdb204735da11f")
wordService.getWord(map)
可以看见HTTP请求的报文如下所示:
HTTP请求报文
Streaming
如果下载小文件可以不使用Streaming。下载大文件使用Streaming可以避免Retrofit将文件写入运行内存中避免OOM。
请求头注解(1个)
名称 | 说明 |
---|---|
Headers | 添加请求头 |
请求头不会相互覆盖,所有具有相同名字的头会包含在请求中。
示例代码如下所示:
@Headers("Cache-Control: max-age=640000", "User-Agent: YourAppName")
@GET("query")
fun getWord(@Query("word") word: String, @Query("dtype") dtype: String,@Query("key") key: String): Call<WordData>
参数注解(12个)
名称 | 说明 |
---|---|
Body | 直接控制Body |
Field | 添加一个表单数据 |
FieldMap | 添加多个表单数据 |
Header | 添加一个请求头 |
HeaderMap | 添加多个请求头 |
Query | 动态拼接一个参数到URL后 |
QueryMap | 动态拼接多个参数到URL后 |
QueryName | 动态拼接无值参数到URL后 |
Path | 替换相应位置参数 |
Url | 直接传入URL |
Part | 表示multi-part一个参数 |
PartMap | 表示multi-part多个参数 |
Body
当你想直接控制POST/PUT的Body时(替代参数或表单样式发送Body),可以直接使用该注释。
@POST("query")
fun getWord(@Body body: RequestBody): Observable<WordData>
var retrofit = Retrofit.Builder()
.baseUrl("http://v.juhe.cn/xhzd/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
var wordService = retrofit.create(WordService::class.java)
val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), "this is body")
wordService.getWord(body)
Field / FieldMap
表单上传数据,Field是上传单个数据,FieldMap是上传多个数据。并且需要使用@FormUrlEncoded修饰请求方法,否则报错。
Field示例代码如下所示:
@FormUrlEncoded
@POST("query")
fun getWord(@Field("word") word: String, @Field("dtype") dtype: String, @Field("key") key: String): Observable<WordData>
FieldMap示例代码如下所示:
var map = mapOf("word" to "你","key" to "c5c6a09be5cdb2")
var retrofit = Retrofit.Builder()
.baseUrl("http://v.juhe.cn/xhzd/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
var wordService = retrofit.create(WordService::class.java)
wordService.getWord(map)
@FormUrlEncoded
@POST("query")
fun getWord(@FieldMap() map: Map<String,String>): Observable<WordData>
Header / HeaderMap
添加请求体,Header是添加单个请求头,HeaderMap添加多个请求头。请求头不会相互覆盖,所有具有相同名字的头会包含在请求中。
Header代码如下所示:
@GET("query")
fun getWord(@Header("User-Agent") name: String, @Query("word") word: String): Observable<WordData>
HeaderMap代码如下所示:
var map = mapOf("Cache-Control" to "max-age=640000","User-Agent" to "YourAppName")
var retrofit = Retrofit.Builder()
.baseUrl("http://v.juhe.cn/xhzd/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
var wordService = retrofit.create(WordService::class.java)
wordService.getWord(map,"你")
@GET("query")
fun getWord(@HeaderMap() name: Map<String,String>, @Query("word") word: String): Observable<WordData>
Query / QueryMap / QueryName
动态添加参数到URL
Query
以下是GET请求示例代码:
//接口
@GET("query")
fun getWord(@Query("word") word: String, @Query("dtype") dtype: String,@Query("key") key: String): Observable<WordData>
var retrofit = Retrofit.Builder()
.baseUrl("http://v.juhe.cn/xhzd/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
var wordService = retrofit.create(WordService::class.java)
wordService.getWord("word","json","c5c6a09be5cdb2")
使用了Query之后,URL会拼接成: http://v.juhe.cn/xhzd/query?word=word&dtype=json&key=c5c6a09be5cdb2
QueryMap
以下是GET请求示例代码:
@GET("query")
fun getWord(@QueryMap() map: Map<String,String>): Observable<WordData>
var wordService = retrofit.create(WordService::class.java)
var map = mapOf("word" to "你","key" to "c5c6a09be5cdb20473")
wordService.getWord(map)
也可以在POST中使用Query或QueryMap,同样是将参数拼接到URL后。
QueryName
动态添加参数到没有值的Url后面,示例代码如下所示:
@GET("query")
fun getWord(@QueryName filter: String): Observable<WordData>
Path
替换URL中相对应的路径。
示例代码如下所示:
@GET("users/{user}/repos")
fun listRepos(@Path("user") user: String): Call<List<Repo>>
var retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
val service = retrofit.create(WordService::class.java)
service.listRepos("octocat")
传递进来的参数会替换掉"users/{user}/repos"中的user部分,如下所示:
https://api.github.com/users/octocat/repos
Url
直接传入Url,代码如下所示:
@GET()
fun getWord(@Url url: String): Observable<WordData>
Part / PartMap
Part表示一个multi-part请求,PartMap表示多个PartMap请求。使用这两个参数需要在接口方法使用Multipart注解。
Part
存在该注解的参数,有以下三种处理方式:
@Multipart
@POST("query")
fun getWord(@Part("name") filter: String): Observable<WordData>
@Multipart
@POST("query")
fun getWord(@Part() body: MultipartBody.Part): Observable<WordData>
@Multipart
@POST("query")
fun getWord(@Part("name") body: MultipartBody): Observable<WordData>
MultipartBody.Part上传文件
var file = File("/sdcard/Pictures/transitions_diagram.png")
var requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file)
var multipartBodyPart = MultipartBody.Part.createFormData("SDFile", file.name, requestFile)
MultipartBody上传文件
var file = File("/sdcard/Pictures/transitions_diagram.png")
var requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file)
var multipartBodyPart = MultipartBody.Part.createFormData("SDFile", file.name, requestFile)
var multipartBody = MultipartBody.Builder().addPart(multipartBodyPart).build()
PartMap
如果参数是RequestBody可以直接使用,如果是map,则需要转换成相应的类型使用,示例代码如下所示:
@Multipart
@POST("/upload")
fun upload(@Part("file") file: RequestBody, @PartMap params: Map<String, RequestBody>): Call<ResponseBody>
总结
结合之前第一篇加上本篇已经涵盖了大多数Retrofit的使用,如果遇到特殊情况需要使用到自定义Converter、CallAdapter、Client。Retrofit的出现我相信作者是为了简化、规范网络请求,因此在使用过程中越简单越好。