Android 最好用的网络库 Retrofit

Android 最好用的网络库 Retrofit,第1张

Android 最好用的网络库 Retrofit

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 请求,传入参数是请求地址的相对路径
    // 返回值是 Retrofit 内置的 Call 类型,通过泛型来指定服务器响应的数据应该转换为什么对象
    @GET("get_data.json")
    fun getAppData(): Call
}

​ 编写一个按钮点击事件,处理具体的网络请求逻辑

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")    // 指定所有 Retrofit 请求的根路径
                    .addConverterFactory(GsonConverterFactory.create()) // 指定 Retrofit 在解析数据时使用的转换库
                    .build()    // 构建 Retrofit 对象
            val appService = retrofit.create(AppService::class.java)
            // 调用 AppService 的 getAppData() 方法,返回 Call
            // 再调用 enqueue() 方法,Retrofit 会根据注解中配置的服务器接口地址进行网络请求
            // 当发起请求时,Retrofit 会自动在内部开启子线程,服务器响应的数据会回调到 Callback 实现里面
            appService.getAppData().enqueue(object : Callback {
                override fun onResponse(call: Call, response: Response) {
                    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, t: Throwable) {
                    t.printStackTrace()
                }
            })
        }
    }
}

处理复杂的接口地址类型

服务器不可能总是提供静态类型的接口,很多场景下,接口地址中的部分内容是会动态变化的,比如如下的接口地址:GET http://example.com//get_data.json,这种接口地址对应到 Retrofit 中该怎么写呢?

interface AppService {

    @GET("{page}/get_data.json")
    fun getData(@Path("page") page: Int): Call
}

部分代表页数,使用一个 {page} 的占位符,又在 getData() 方法添加一个 page 参数,使用 @Path("page") 注解声明这个参数

针对这种接口:GET http://example.com/get_data.json?u=$t=,Retrofit 专门提供了一种语法支持

interface AppService {

    @GET("get_data.json")
    fun getData(@Query("u") user: String, @Query("t") token: String): Call
}

除了 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
}

有些服务器接口还会要求我们在 HTTP 请求的 header 中指定参数

interface AppService {

    @Headers("User-Agent: okhttp", "Cache-Control: max-age=0")
    @GET("get_data.json")
    fun getData(): Call
}

以及动态指定 header 的值

interface AppService {

    @GET("get_data.json")
    fun getData(@Header("User-Agent") userAgent: String,
                    @Header("Cache-Control") cacheControl: String): Call
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5692513.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存