Retrofit使用说明书

【产品名称】

Retrofit

【产品介绍】

Retrofit是目前比较流行的Android 网络请求框架Retrofit主页,他是基于OkHttp进行了进一步封装,真正进行网络请求工作的是OKHttp,但是Retrofit 利用动态代理等处理,让开发者使用一些注解、很简单的代码就实现网络请求。(用了都说好,哈哈😄),关于Retrofit的是如何工作的可以看看我上一篇写的源码面前无秘密之——Retrofit 源码分析,本文主要探讨Retrofit的使用。

为了方便介绍Retrofit 使用Spring boot 搭建了一个简单的api,方便下面介绍Retrofit使用

【产品成分】

就那么多代码 源代码

【产品使用】

上面都不重点,正文开始,上车🚲走起

一、准备工作,引入依赖

implementation 'com.squareup.retrofit2:retrofit:2.8.1'

二、写点代码,给我来个(Retrofit)对象

1.根据api 定义对应接口
interface ApiService {
    /**
     * GET 请求方式 路由 friend_list
     * 请求参数是 page
     * 相应数据是json格式,根据json数据格式来定义方法返回类型
     *返回值是Call包裹的,可以调用execute或enqueue发起网络请求
     */
    @GET("friend_list")
    fun getFriends(@Query("page") page:Int=1): Call<Result<List<User>>>
}

2. 创建retrofit 实例
        val retrofit = Retrofit.Builder()
                //api的baseUrl
                .baseUrl("http:192.168.31.7:8080/")
                // ① 添加一个Gson转换器,用于把请求到的json数据转换成对应的java对象
                .addConverterFactory(GsonConverterFactory.create())
                .build()
        //使用create方法创建ApiService 接口实例
        val apiService = retrofit.create(ApiService::class.java)

**说明:**在①处需要添加一个依赖 implementation 'com.squareup.retrofit2:converter-gson:2.8.1' 网络请求一般返回的是Json数据,使用GsonConverterFactory 它可以帮我们自动把请求到的json数据转换为对应的java对象

三、发起一个网络请求

     apiService.getFriends().enqueue(object : Callback<Result<List<User>>> {
            override fun onFailure(call: Call<Result<List<User>>>, t: Throwable) {
                Log.i("MainActivity","${t.message}")
            }
            override fun onResponse(call: Call<Result<List<User>>>, response: Response<Result<List<User>>>) {
                if (response.isSuccessful) {
                    Log.i("MainActivity","success")
                    Log.i("MainActivity",response.body().toString())
                }else{
                    Log.i("MainActivity","http code=${response.code()},message=${response.message()}")
                }
            }
        })

解释说明: getFriends() 方法返回值是Call对象,调用enqueue 发起异步请求,enqueue参数是CallBack接口,它有两个方法回调 网络请求失败、异常走onFailure ,网络请求有响应走onResponse 方法。onFailureonResponse 方法 回调都是在主线程调用的,不需要我们切回主线程。 一般我们说的网络请求成功了都是HTTP code==200的时候, onResponse并不是只有code==200 才走的,它只是说明请求有相应,具体是否是我们想要的成功还需使用 response.isSuccessful 方法判断,这个方法认为HTTP code属于[200,300)区间内都是成功的。

Retofit要求java8+和android 21+的支持,所以需要在模块的build.gradle文件的 android{ } 配置如下

android{
		...
    	compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

       kotlinOptions{
        jvmTarget="1.8"
    }    
}

如果没有上面配置 编译时就会出现这个错误提示
java.util.concurrent.ExecutionException: com.android.tools.r8.a: Invoke-customs are only supported starting with Android O (–min-api 26)

四、如何根据api 定义我们的接口方法

1. GET请求 提交表单传参 ( @Query)

api : 请求方式 GET …/friend_list?page=1&sort=desc
参数 page 、sort GET请求方法是把参数拼接到URL上的。通过?连接参数多个参数之间同&分割
响应结果:

{
  "code": 0,
  "msg": "success",
  "data": [
    {
      "id": 2,
      "email": "abc@qq.com",
      "name": "Li",
      "sex": 1,
      "age": 20,
      "avatar": "https://212"
    },
    ...
  ]
}

Retrofit 方法定义

   @GET("friend_list")
    fun getFriends(
        //通过Query注解定义参数注解的value值就是请求参数名
        @Query("page") page: Int = 1,
        @Query("sort") sort: String
    ): Call<Result<List<User>>>

2. POST请求提交表单 (@Field)

api : 请求方法 POST …/login
参数 email、password 这些参数是在请求body中的
响应数据

{
    "code": 0,
    "msg": "success",
    "data": {
        "id": 3,
        "email": "kk@gmail.com",
        "name": "Emily",
        "sex": 1,
        "age": 20,
        "avatar": "https://111"
    }
}

Retrofit 方法定义

    @FormUrlEncoded
    @POST("login")
    fun login(
        @Field("email") email: String,
        @Field("password") password: String
    ): Call<Result<User?>>

**解释说明: **请求参数使用@Field注解,方法处理需要添加POST注解外,还需要添加 @FormUrlEncoded 注解否则会报错。 添加这个注解就会在请求Headers 添加Content-Type=application/``x-www-form-urlencoded 这样请求表单参数数据就会通过URL编码格式编码 参考链接

3. 动态URL,路由参数 (@Path)

api : 请求方式GET …/user/{id}
参数 id,通过/拼接到请求的url上
响应数据

{
  "code": 0,
  "msg": "success",
  "data": {
    "id": 1,
    "email": "xxx@xx.com",
    "name": "xxxx",
    "sex": 1,
    "age": 20,
    "avatar": "https://xxxx"
  }
}

Retrofit 方法定义

    @GET("user/{id}")
    fun getUserInfo(@Path("id") id: Int): Call<Result<User?>>

解释说明: url中可变的部分用{xxx} 表示,请求的时候,使用@Path 的参数值会把{xxx} 替换掉,@Path的value值要和路由中定义的{xxxx} 大括号中的值相同。例如 如果是调用getUserInfo(2) 那个请求的就是.../user/2 这个地址。

4.提交json数据 (@Body)

api :请求方式POST …/add_book
请求参数 是json数据格式如下

{
  "name": "《第一行代码》",
  "author": "郭霖",
  "desc": "xxxxx",
  "cover": "xxxxx"
}

响应数据:

{
  "code": 0,
  "msg": "success",
  "data": {
    "name": "《第一行代码》",
    "author": "郭霖",
    "desc": "xxxxx",
    "cover": "xxxxx"
  }
}

Retrofit 方法定义

    @POST("add_book")
    fun addBook(@Body book: Book): Call<Result<Book>>

5.POST 提交带文件的表单,上传文件

api: 请求方式POST …/modify_user_info
请求参 name (字符串)、avatar (文件)
响应结果

{
    "code": 0,
    "msg": "success",
    "data": null
}

Retrofit 方法定义
第一种方式

    @Multipart
    @POST("modify_user_info")
    fun modifyUserInfo(
        @Part("name") name: String,
        @Part file: MultipartBody.Part
    ): Call<Result<Nothing?>>

**解释说明:**使用@Multipart 即就是设置Content-Type=``multipart/form-data 表单中可以带文件,在方法参数前加上@Part 注解,普通key-value 要在@Part 注解中声明value的值,MultipartBody.Part参数则不能填value值。下面说说则么创建MultipartBody.Part

		//第一步, 根据文件或字节数据创建RequestBody对象 
		val requestBody = RequestBody.create(MultipartBody.FORM, imageData)
        //添加文件,第一个参数是api要求的参数、第二个参数是要发送文件的文件名称,第三个参数是文件数据对应的RequestBody
        val part = MultipartBody.Part.createFormData("avatar", "android_logo.png", requestBody)


第二种方式,直接传入RequestBody 对象

  @POST("modify_user_info")
    fun modifyUserInfo(@Body body: RequestBody): Call<Result<Nothing?>>

关于RequestBody创建如下

		//与上面一种方式相同 先根据文件或字节数据创建RequestBody对象 
        val imageDataBody = RequestBody.create(MultipartBody.FORM, imageData)
        //构建一个表单body
        val multipartBody = MultipartBody.Builder()
                //添加普通的key-value 表单数据
            .addFormDataPart("name", "kk")
                //添加文件,第一个参数是api要求的参数、第二个参数是要发送文件的文件名称,第三个参数是文件数据对应的RequestBody
            .addFormDataPart("avatar", "android_logo.png", imageDataBody)
            .build()

如果有多个文件就多添加几个addFormDataPart

6.其它的一些注解

1、@Url
不指定@GET、@POST等直接指定路由,而是在方法的参数上用@Url 修饰,通过传入的参数不同,动态改变请求的路由地址。eg.

    @GET
    fun getData(@Url url:String, @Query("page") page: Int = 1): Call<Result<List<User>>>

我觉得一般可以用于参数和返回值相同的一类 api上。

  1. @QueryMap

当参数多但又不确定个数,就可以用@XXXMap (@QueryMap@FieldMap@PartMap)类注解。eg.

    @GET("friend_list")
    fun getData(@QueryMap map: Map<String,String>): Call<Result<List<User>>>

@QueryMap、@FieldMap、@PartMap 也是类似

五、ConverterFactory

converterFactory 转换工厂负责将网络返回的数据转化为对应的java数据类型。 Retrofit 默认有一个BuiltInConverters 工厂 将返回的数据转化为okhttp3.ResponseBody 对象。上面的例子中我们构建Retrofit对象时通过addConverterFactory(GsonConverterFactory.create()) 方法添加了一个GsonConverterFactory工厂。如果没有添加这个我们上面接口返回值就要改一改了

 @GET("friend_list")
    fun getData(@QueryMap map: Map<String,String>): Call<ResponseBody>

Retrofit官方给我们提供了一些转换器工厂,比如xml、Jackson等。有时候我们可以需要Json字符串,不要转换成对应的对象,那么我们可以将返回值写成ResponseBody 然后自己处理流数据,这也是一种办法,但太麻烦了,这时候就可以用ScalarsConverterFactory转换工厂(需要导入 implementation ``'``com.squareup.retrofit2:converter-scalars``:``(insert latest version)``'``) 它会把请求的数据转换为String。及方法返回值写成Call 即可。

六. kotlin 协程的支持

用法很简单,在方法前添加suspend ,返回结果不需要用Call包裹,直接返回想要的结果,如下


    @GET("user/{id}")
    suspend fun getUserInfo1(@Path("id") id: Int):Result<User?>

更多细节可以参考我之前写的文章 kotlin 协程在 Android 中的使用——Jetpack 中的协程、Retofit中使用协程及源码分析

【生产企业】

Square


最近去医院拿了点药💊喝,看药品的说明书结构还挺清晰,就仿药品说明方式写这篇文章(就是感觉好玩)。大家敲代码同时,也要注意身体,多多锻炼。身体好才是最重要的。不说了,喝药去了

参考链接

1.表单数据
2.Retrofit主页


本文相关源码地址

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值