Retrofit
Retrofit 是一个网络请求类,通过注解的形式进行简化代码,网络请求需要申请权限,点击查看网络权限申请
点击查看Retrofit最新版本
导入库
kotlin
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.6.2' //返回数据转换成json对象1
2
2
Get 请求示例
假设有接口http://api.myhug.cn/z/home,首先创建一个接口类 API API类内部用获取的方法
kotlin
import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.http.GET
interface API {
// get 请求
@GET("z/home")
fun getJson(): Call<ResponseBody>
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
// 开始请求
kotlin
// 创建retrofit
val retrofit = Retrofit.Builder().baseUrl("http://api.myhug.cn/").build()
// 创建server实例
val api = retrofit.create(API::class.java)
val task = api.getJson()
// 开始请求
task.enqueue(object : Callback<ResponseBody>{
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
Log.d("TAG", "onFailure: + ${t.toString()}")
}
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
if (response.code() == HttpURLConnection.HTTP_OK){
// 这里有个坑,response.body()?.string() 只能被调用一次,谨记,打印要记得去掉
Log.d("TAG", "onResponse: ${response.body()?.string()}")
}
}
})1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
返回数数据转换成对象
- 创建数据对象使用插件 java使用gsonformat kotlin使用JsonKotlin
- 使用gson第三方库,在创建请求时,把对应的请求体转过去
kotlin
// 获取返回数据
val result = response.body()?.string()
val gson = Gson()
val jsonResult = gson.fromJson(result,JsonData::class.java)1
2
3
4
2
3
4
简单点的方法是直接在网络请求时,要求返回一个对象,使用gson第三方库完成
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'1
API接口类,直接返回对象
kotlin
interface API {
// get 请求
@GET("z/home")
fun getJson(): Call<JsonData>
}1
2
3
4
5
2
3
4
5
创建retrofit时,增加json序列化对象
kotlin
// 创建retrofit
val retrofit = Retrofit.Builder().baseUrl("http://api.myhug.cn/").addConverterFactory(GsonConverterFactory.create()).build()
// 创建server实例
val api = retrofit.create(API::class.java)
val task = api.getJson()
// 开始请求
task.enqueue(object : Callback<JsonData>{
override fun onFailure(call: Call<JsonData>, t: Throwable) {
Log.d("TAG", "onFailure: + ${t.toString()}")
}
override fun onResponse(call: Call<JsonData>, response: Response<JsonData>) {
if (response.code() == HttpURLConnection.HTTP_OK){
Log.d("TAG", "onResponse: ${response.body()}")
}
}
})1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
上传文件
创建接口,使用part参数
kotlin
// post 上传单个文件
@Multipart
@POST("/file/upload")
fun postFile(@Part part: MultipartBody.Part):Call<ResponseBody>1
2
3
4
2
3
4
进行请求,需要动态申请权限
kotlin
fun retrofitPost(){
// 获取图片地址
val file = File("/etc/mmi/pass.png")
val body = RequestBody.create(MediaType.parse("image/png"),file)
val part = MultipartBody.Part.createFormData("file",file.name,body)
val retrofit = Retrofit.Builder().baseUrl("http://192.168.11.141:9102/").addConverterFactory(GsonConverterFactory.create()).build()
val api = retrofit.create(API::class.java)
val task = api.postFile(part)
task.enqueue(object :Callback<ResponseBody>{
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
Log.d("TAG", "onFailure: + ${t.toString()}")
}
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
Log.d("TAG", "onResponse: ${response.body()?.string()}")
}
})
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
表单提交
kotlin
// 表单提交
@FormUrlEncoded
@POST("login")
fun doLogin(@Field("userName") userName: String,@Field("password") word: String):Call<loginResult>1
2
3
4
2
3
4
kotlin
fun login(){
val retrofit = Retrofit.Builder().baseUrl("http://192.168.11.141:9102/").addConverterFactory(GsonConverterFactory.create()).build()
val api = retrofit.create(API::class.java)
val task = api.doLogin("1","2")
task.enqueue(object :Callback<loginResult>{
override fun onFailure(call: Call<loginResult>, t: Throwable) {
Log.d("TAG", "onFailure: + ${t.toString()}")
}
override fun onResponse(call: Call<loginResult>, response: Response<loginResult>) {
Log.d("TAG", "onResponse: ${response.body()}")
}
})
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
图片下载
kotlin
// 下载请求
fun downFile(){
val retrofit = Retrofit.Builder().baseUrl("http://192.168.11.141:9102/").build()
val api = retrofit.create(API::class.java)
val task = api.downFile("download/8")
task.enqueue(object :Callback<ResponseBody>{
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
Log.d("TAG", "onFailure: + ${t.toString()}")
}
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
val headers = response.headers()
val fileNameHeader = headers.get("Content-disposition")
var fileName = "未命名.png"
if (fileNameHeader != null) {
fileName = fileNameHeader.replace("attachment; filename=","")
writeToFile(response,fileName)
}
// 获取文件名字在哪个字典中,文件名字一般在headers中,需要遍历找到
for (i in 0 until headers.size()) {
val value = headers.value(i)
val key = headers.name(i)
Log.d("TAG", "onResponse: $key ++ $value")
}
}
})
}
// 异步下载文件
private fun writeToFile(response: Response<ResponseBody>, fileName: String) {
Thread{
kotlin.run {
val inputStream = response.body()?.byteStream()
val baseOutFile = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val outFile = File(baseOutFile,fileName)
Log.d("TAG", "outFile: == >>> $outFile")
try {
if (inputStream != null){
val fos = FileOutputStream(outFile)
val buffer = ByteArray(1024)
var len = 0
while (inputStream.read(buffer).apply { len = this } > 0){
fos.write(buffer,0,len)
}
fos.close()
}
}catch (e: Exception){
e.printStackTrace()
}
}
}.start()
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
接口注解示范
kotlin
interface API {
// get 请求
@GET("z/home")
fun getJson(): Call<JsonData>
// @Query 注解
@GET("z/home")
fun getWithQueryParams(@Query("page") page: Int): Call<ResponseBody>
// @QueryMap 注解
@GET("z/home")
fun getWithQueryMapParams(@QueryMap map: Map<String,String>): Call<JsonData>
// @Url 注解
@GET()
fun getWithUrl(@Url url: String,@QueryMap map: Map<String,String>): Call<JsonData>
// post 请求 @Body注解 CommentBody是一个数据类
@POST("post/comment")
fun postWithBody(@Body body :CommentBody):Call<ResponseBody>
// post 上传单个文件
@Multipart
@POST("/file/upload")
fun postFile(@Part part: MultipartBody.Part):Call<ResponseBody>
// 表单提交
@FormUrlEncoded
@POST("login")
fun doLogin(@Field("userName") userName: String,@Field("password") word: String):Call<loginResult>
// 添加header
@POST("post/comment")
fun getHeader(@Header("client") client: String) :Call<ResponseBody>
// 添加headers
@Headers("client: android")
@POST("post/comment")
fun getHeaders() :Call<ResponseBody>
// 添加headerMap
@POST("post/comment")
fun getHeaderMap(@HeaderMap map: Map<String,String>) :Call<ResponseBody>
// 文件下载
@Streaming
@GET
fun downFile(@Url url: String) :Call<ResponseBody>
// 动态修改请求路径
@GET("group/{id}/users")
fun groupList(@Path("id") groupId: Int):Call<ResponseBody>;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
注解
请求方法注解
@GET @POST @DELETE @PUT @PATH @OPTIONS @HEAD
请求参数注解
| 注解 | 方法含义 |
|---|---|
| @Body | Post提交数据时的body |
| @Filed | Post提交数据时的表单字段 |
| @FiledMap | Post提交数据时的表单字段集合 |
| @PartMap | 上传文件和参数时 |
| @Part | 上传文件时使用 |
| @Query | url参数 |
| @QueryMap | url参数集合 |
| @Url | 请求路径 |
请求头注解
请求头header有三种注解方式,@Header、@Headers、@HeaderMap
标记注解
| 注解 | 方法含义 |
|---|---|
| @Streaming | 文件流 |
| @Multipart | 上传 |
| @FormUrlEncode | 表单提交 |
编译报错
1.译失败:Error: Invoke-customs are only supported starting with Android O (--min-api 26)
kotlin
build.gradle文件中android节点下增加:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}1
2
3
4
5
6
2
3
4
5
6
- 注意 返回值
response.body().string()只能被调用一次
//图片来源: 阳光沙滩