Retrofit的使用 | 青训营笔记

104 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的第7天

Retrofit同样是一款由Square公司开发的网络库,但是它和OkHttp的定位完全不同。OkHttp侧重的是底层通信的实现,而Retrofit侧重的是上层接口的封装。事实上,Retrofit就是Square公司OkHttp的基础上进一步开发出来的应用层网络通信库,使得我们可以用更加面向对象的思维进行网络操作

基本使用

Retrofit的基本设计思想

  • 首先我们可以配置好一个根路径,然后在指定服务器接口地址时只需要使用相对路径即可,这样就不用每次都指定完整的URL地址了
  • Retrofit允许我们对服务器接口进行归类,将功能同属一类的服务器接口定义到同一个接口文件当中,从而让代码结构变得更加合理
  • 我们也完全不用关心网络通信的细节,只需要在接口文件中声明一系列方法和返回值,然后通过注解的方式指定该方法对应哪个服务器接口,以及需要提供哪些参数。当我们在程序中调用该方法时,Retrofit会自动向对应的服务器接口发起请求,并将响应的数据解析成返回值中声明的类型。这就使得我们可以用更加面向对象的思维来进行网络操作

使用

  1. 首先添加依赖库
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
 implementation 'com.squareup.retrofit2:converter-gson:2.6.1'

由于Retrofit是基于OkHttp开发的,因此添加上述第一条依赖会自动将Retrofit、OkHttp和Okio这几个库一起下载,另外它是借助GSON来解析JSON数据的,所以会自动将GSON库一起下载下来

  1. 定义一个接收JSON数据的转化类App,属性与JSON字段匹配
class App(val id: String, val name: String, val version: String)

定义一个获取JSON数据的接口

interface AppService {
// 只需要传入请求地址的相对路径
 @GET("get_data.json")
 // 返回值必须声明成Retrofit中内置的Call类型,并通过泛型来指定服务器响应的数据应该转换成什么对象
 fun getAppData(): Call<List<App>>
}
  1. 处理网络请求逻辑
getAppDataBtn.setOnClickListener {
val retrofit = Retrofit.Builder()
        //根路径
        .baseUrl("http://localhost/")
        // 指定Retrofit在解析数据时所使用的转换库
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    // 创建一个该接口的动态代理对象
    val appService = retrofit.create(AppService::class.java)
    // 根据注解中配置的服务器接口地址去进行网络请求了
    appService.getAppData().enqueue(object : Callback<List<App>> {
        override fun onResponse(call: Call<List<App>>,
                                response: Response<List<App>>) {
            // 得到Retrofit解析后的对象                    
            val list = response.body()
            if (list != null) {
                for (app in list) {
                    Log.d("MainActivity", "id is ${app.id}")
                    Log.d("MainActivity", "name is ${app.name}")
                    Log.d("MainActivity", "version is ${app.version}")
                }
            }
        }
        override fun onFailure(call: Call<List<App>>, t: Throwable) {
            t.printStackTrace()
        }
    })
} 

处理复杂的接口地址类型

  • 当实现分页处理时页数会发生变化,这时候可以使用了{page}的占位符,并在方法使用@Path("page")注解来声明这个参数
@GET("{page}/get_data.json")
fun getData(@Path("page") page: Int): Call<Data>
  • 当请求需要带参数时
@GET("get_data.json")
fun getData(@Query("user") user: String, @Query("token") token: String): Call<Data>
  • 同时Retrofit对所有常用的HTTP请求类型都进行了支持,使用@GET、@POST、@PUT、@PATCH、@DELETE注解,就可以让Retrofit发出相应类型的请求了
@DELETE("data/{id}")
 fun deleteData(@Path("id") id: String): Call<ResponseBody>

// 当Retrofit发出POST请求时,就会自动将Data对象中的数据转换成JSON格式的文本
@POST("data/create")
 fun createData(@Body data: Data): Call<ResponseBody>

Retrofit构建器的最佳写法

想要得到AppService的动态代理对象,需要先使用Retrofit.Builder构建出一个Retrofit对象,然后再调用Retrofit对象的create()方法创建动态代理对象,因为构建出的Retrofit对象是全局通用的,只需要在调用create()方法时针对不同的Service接口传入相应的Class类型即可。因此,我们可以将通用的这部分功能封装起来,从而简化获取Service接口动态代理对象的过程。

新建一个ServiceCreator单例类:

object ServiceCreator {

 private const val BASE_URL = "http://10.0.2.2/"

 private val retrofit = Retrofit.Builder()
 .baseUrl(BASE_URL)
 .addConverterFactory(GsonConverterFactory.create())
 .build()
 fun <T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)

}

获取一个AppService接口的动态代理对象,只需要使用如下写法即可

val appService = ServiceCreator.create(AppService::class.java)

参考资料

第一行代码——Android(第3版)