Retrofit 同样是一款由 Square 公司开发的网络库,更侧重于对上层接口的封装
基本用法
通常,服务器提供的接口是按功能归类的,比如新增用户、修改用户数据、查询用户数据等可以归为一类,上架图书,查询在架图书等又可以归为一类。这样的归类能让代码结构变得更加合理,提供可阅读性和可维护性
Retrofit 的用法就是基于以上几点设计的,我们可以对服务器接口进行归类,将功能同属一类的服务器接口定义到同一个接口文件中,从而让代码结构变得更加合理
最后,我们无需关心网络通信的细节,只需在接口文件中声明一系列方法和返回值,然后通过注解的方式指定该方法对应哪个服务器接口,以及需要提供哪些参数。当我们在程序调用该方法时,Retrofit 会自动向对应的服务器接口发起请求,并将响应数据解析成返回值声明的类型
要想使用 Retrofit,我们需要在项目中添加必要的依赖库。编辑 app/build.gradle 文件,在 dependencies 闭包中添加如下内容:
dependencies {
...
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
implementation 'com.squareup.retrofit2:converter:2.6.1'
}
上述第二条依赖是 Retrofit 的转换库,借助 GSON 来解析 JSON 数据。由于 Retrofit 会借助 GSON 将 JSON 数据转换对象,因此这里需要新增一个 App 类,并加入 id、name 和 version 三个字段
class App (val id: String, val name: String, val version: String)
接下来,我们可以根据服务器接口的功能进行归类,创建不同种类的接口文件,并在其中定义对应具体服务器接口的方法
interface AppService {
@GET("get_data.json")
fun getAppData(): Call<List<App>>
}
? 编写一个按钮点击事件,处理具体的网络请求逻辑
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
val retrofit = Retrofit.Builder()
.baseUrl("http://127.0.0.1")
.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>>) {
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()
}
})
}
}
}
处理复杂的接口地址类型
服务器不可能总是提供静态类型的接口,很多场景下,接口地址中的部分内容是会动态变化的,比如如下的接口地址:GET http://example.com/<page>/get_data.json ,这种接口地址对应到 Retrofit 中该怎么写呢?
interface AppService {
@GET("{page}/get_data.json")
fun getData(@Path("page") page: Int): Call<Date>
}
<page> 部分代表页数,使用一个 {page} 的占位符,又在 getData() 方法添加一个 page 参数,使用 @Path("page") 注解声明这个参数
针对这种接口:GET http://example.com/get_data.json?u=<user>$t=<token> ,Retrofit 专门提供了一种语法支持
interface AppService {
@GET("get_data.json")
fun getData(@Query("u") user: String, @Query("t") token: String): Call<Data>
}
除了 GET 请求,常用的还有 POST 请求,如果我们需要向服务器提交数据该怎么写呢?
POST http://example.com/data/create
{"id": 1, "content": "The description for this data"}
使用 POST 请求来提交数据,需要将数据放到 HTTP 请求的 body 部分,这个功能在 Retrofit 中可以借助 @Body 注解来完成
interface AppService {
@POST("/data/create")
fun createData(@Body data: Data): Call<ResponseBody>
}
有些服务器接口还会要求我们在 HTTP 请求的 header 中指定参数
interface AppService {
@Headers("User-Agent: okhttp", "Cache-Control: max-age=0")
@GET("get_data.json")
fun getData(): Call<Data>
}
以及动态指定 header 的值
interface AppService {
@GET("get_data.json")
fun getData(@Header("User-Agent") userAgent: String,
@Header("Cache-Control") cacheControl: String): Call<Data>
}
|