Android网络笔记:Retrofit

本文详细介绍了如何在Android应用中使用Retrofit 2.6.1库进行网络请求,包括添加依赖、定义接口、实体类、网络请求处理和复杂接口地址的处理。通过实例展示了如何构造Retrofit对象、发送GET请求并解析服务器响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需要先在项目中添加必要的依赖库。编辑app/build.gradle文件,在dependencies闭包中添加如下内容:

dependencies {
    ...
    implementation 'com.squareup.retrofit2:retrofit:2.6.1'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
}

使用举例
1.新增一个实体类App类

data class App(val id: String, val name: String, val version: String)

2.定义一个接口文件,新建AppService接口

interface AppService {

    @GET("get_data.json")
    fun getAppData(): Call<List<App>>

}

上述代码中有两点需要我们注意。第一就是在getAppData()方法上面添加的注解,这里使用了一个@GET注解,表示当调用getAppData()方法时Retrofit会发起一条GET请求,请求的地址就是我们在@GET注解中传入的具体参数。注意,这里只需要传入请求地址的相对路径即可,根路径我们会在稍后设置。

第二就是getAppData()方法的返回值必须声明成Retrofit中内置的Call类型,并通过泛型来指定服务器响应的数据应该转换成什么对象。由于服务器响应的是一个包含App数据的JSON数组,因此这里我们将泛型声明成List。当然,Retrofit还提供了强大的Call Adapters功能来允许我们自定义方法返回值的类型。

3.在activity_main.xml中定义一个按钮来测试Retrofit网络请求事件,我们在它的点击事件中处理具体的网络请求逻辑即可。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/getAppDataBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Get App Data" />

</LinearLayout>

现在修改MainActivity中的代码:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        getAppDataBtn.setOnClickListener {
            //来构建一个Retrofit对象
            //baseUrl用于指定所有Retrofit请求的根路径
            val retrofit = Retrofit.Builder().baseUrl("url")
                //指定Retrofit在解析数据时所使用的转换库,这里指定成GsonConverterFactory
                .addConverterFactory(GsonConverterFactory.create())
                .build()
            //创建一个该接口的动态代理对象
            val appService = retrofit.create(AppService::class.java)
            //当调用了AppService的getAppData()方法时,会返回一个Call<List<App>>对象,
            // 这时我们再调用一下它的enqueue()方法,Retrofit就会根据注解中配置的服务器接口地址去进行网络请求了,
            // 服务器响应的数据会回调到enqueue()方法中传入的Callback实现里面。
            //当发起请求的时候,Retrofit会自动在内部开启子线程,当数据回调到Callback中之后,
            // Retrofit又会自动切换回主线程,整个操作过程中我们都不用考虑线程切换问题。
            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()
                }
            })
        }
    }
}

4.处理复杂的接口地址类型
首先先定义一个实体类Data

data class Data(val id: String, val content: String)

情况一:接口地址是静态的,永远不会改变。那么对应到Retrofit当中,使用如下的写法即可:

GET http://example.com/get_data.json
interface ExampleService {

    @GET("get_data.json")
    fun getData(): Call<Data>

}

情况二:在很多场景下,接口地址中的部分内容可能会是动态变化的。当该方法发起请求时,Retrofit就会自动将page参数的值替换到占位符的位置,从而组成一个合法的请求地址。

GET http://example.com/<page>/get_data.json
interface ExampleService {

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

}

情况三:当我们需要传入一系列参数时:这是一种标准的带参数GET请求的格式。接口地址的最后使用问号来连接参数部分,每个参数都是一个使用等号连接的键值对,多个参数之间使用“&”符号进行分隔。

GET http://example.com/get_data.json?u=<user>&t=<token>
interface ExampleService {

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

}

这里在getData()方法中添加了user和token这两个参数,并使用@Query注解对它们进行声明。这样当发起网络请求的时候,Retrofit就会自动按照带参数GET请求的格式将这两个参数构建到请求地址当中。

情况四:Retrofit对所有常用的HTTP请求类型都进行了支持,使用@GET、@POST、@PUT、@PATCH、@DELETE注解,就可以让Retrofit发出相应类型的请求了。

DELETE http://example.com/data/<id>
interface ExampleService {

//由于POST、PUT 、PATCH、DELETE这几种请求类型与GET请求不同,它们更多是用于操作服务器上的数
//据,而不是获取服务器上的数据,所以通常它们对于服务器响应的数据并不关心。这个时候就可以使用
//ResponseBody,表示Retrofit能够接收任意类型的响应数据,并且不会对响应数据进行解析。
    @DELETE("data/{id}")
    fun deleteData(@Path("id") id: String): Call<ResponseBody>
    

}

情况五:如果我们需要向服务器提交数据该怎么写呢?

POST http://example.com/data/create
{"id": 1, "content": "The description for this data."}
interface ExampleService {

//使用POST请求来提交数据,需要将数据放到HTTP请求的body部分,这个功能在Retrofit中可以借助@Body注解来完成:这样当Retrofit发出POST请求时,就会自动将Data对象中的数据转换成JSON格式的文本,并放到HTTP请求的body部分,服务器在收到请求之后只需要从body中将这部分数据解析出来即可。这种写法同样也可以用来给PUT、PATCH、DELETE类型的请求提交数据。
    @POST("data/create")
    fun createData(@Body data: Data): Call<ResponseBody>
    

}

情况六:有些服务器接口还可能会要求我们在HTTP请求的header中指定参数

GET http://example.com/get_data.json
User-Agent: okhttp
Cache-Control: max-age=0
interface ExampleService {

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

}
//如果想要动态指定header的值
interface ExampleService {

//现在当发起网络请求的时候,Retrofit就会自动将参数中传入的值设置到
//User-Agent和Cache-Control这两个header当中,从而实现了动态指定header值的功能。
    @GET("get_data.json")
    fun getData(@Header("User-Agent") userAgent: String,
        @Header("Cache-Control") cacheControl: String): Call<Data>

}
//retrofit 最佳写法
object RetrofitUtil {
    val retrofit = Retrofit.Builder().baseUrl("127.0.0.1:8080")
        .addConverterFactory(GsonConverterFactory.create()).build()

    fun <T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)

    inline fun <reified T> create(): T = create(T::class.java)
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值