99.Retrofit的基本用法 【附:API概念】

一、Retrofit 简介

Retrofit 是一个由 Square 出品的类型安全的 HTTP 网络请求库。它能够将 HTTP API 映射为接口,并以注解的方式定义请求方法和路径。开发者只需要定义接口,Retrofit 会负责发送网络请求、解析响应数据,并返回相应的对象。

二、添加依赖

在开始使用 Retrofit 之前,我们需要在项目的 build.gradle 文件中添加相关依赖。一般来说,Retrofit 通常搭配以下几个依赖使用:

  • Retrofit 主库
  • Retrofit 的转换器,例如 GsonConverterFactory(用于将 JSON 数据转换为 Java/Kotlin 对象)
  • (可选)OkHttp(Retrofit 底层使用的 HTTP 客户端)

例如,在 app/build.gradle 文件中添加如下依赖:

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    // 另外如果需要日志拦截器
    implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
}

先来插个API的概念:(你可以先sync一下上面的来看这个)

API 是“应用程序编程接口”(Application Programming Interface)的缩写。简单来说,API 是一组规则和协议,这些规则和协议定义了不同软件组件之间如何相互交互和通信。下面我们从几个角度来详细说明 API 的含义和作用:

  1. 定义功能:
    API 规定了软件、服务或库可以提供哪些功能以及如何调用这些功能。开发者可以通过调用这些预定义好的接口来利用现有的功能,而不需要关心内部实现的细节。

  2. 软件组件之间的通信:
    在大型软件系统中,不同模块、库或者服务经常需要协同工作。API 就像一个桥梁,使得各个部分可以使用统一的方式进行数据交换和功能调用。例如,当你调用一个网络 API(比如 RESTful API)时,请求被发送到服务器,服务器按照 API 的约定返回数据给客户端,客户端再根据这些数据进行后续处理。

  3. 隐藏实现细节:
    API 提供了抽象的接口,屏蔽了具体的实现细节。使用者不必了解如何实现该功能,只需要按照 API 提供的规范调用接口即可。这提高了系统的模块化和安全性,同时也使得代码更容易维护和扩展。

  4. 常见的 API 类型:

    • Web API(网络 API):通过 HTTP 协议调用的接口,如 RESTful API、GraphQL 等,常用于前后端分离的应用。
    • 操作系统 API:操作系统为应用程序提供的接口,如文件系统、网络、硬件操作接口等。
    • 库或框架的 API:如 Android SDK、Java API、Retrofit 的接口等,帮助开发者更方便地利用现有的功能库进行开发。
  5. 举例说明:
    比如,在 Android 开发中,你可能会使用 Retrofit 库来请求网络数据。在这种情况下,Retrofit 定义了如何通过注解来描述 HTTP 请求 (例如 GET、POST 方法等),然后根据你的接口定义自动生成实现代码。你只需要关注 API 的调用,而无需手动处理底层的 HTTP 通信逻辑。

三、创建 API 接口

Retrofit 采用接口的方式来定义 API。例如,假设我们请求一个用户信息接口 GET /users/{id},接口可能返回一个 JSON 数据,我们可以定义如下数据模型和接口方法:

User.kt:

package com.example.myapplication

/*
它的作用是用来表示用户的信息
并且 Kotlin 编译器会自动为它生成一些常用的方法,例如 equals(), hashCode(), toString(), copy() 等。

在 Retrofit 中的作用:
在 Retrofit 中,User 类通常用于表示从 API 接口返回的 JSON 数据
当 Retrofit 接收到服务器返回的 JSON 数据时,它会使用 Gson 或其他 JSON 转换器将 JSON 数据自动转换为 User 对象。
 */
data class User(
    val id: Int,
    val name: String,
    val email: String
)

下面是定义 API 接口的代码示例:

package com.example.myapplication
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Path


/*
接口使用 Retrofit 库定义了一个用于获取用户信息的 API 接口

它通过注解的方式声明了一个 HTTP GET 请求,并指定了请求路径和参数
该接口定义了一个 getUser 方法,该方法接收一个用户 ID 作为参数,并返回一个 Call<User> 对象,用于发起网络请求并获取用户信息。

接口是一种抽象类型,用于声明一组方法,但不提供方法的具体实现。
作用:定义一个 API 接口,用于声明网络请求方法。

@GET("users/{id}"): 这是一个注解,用于声明一个 HTTP GET 请求。
@GET: 表示这是一个 GET 请求。
"users/{id}": 表示请求的 URL 路径。 {id} 是一个占位符,用于表示用户 ID。
作用:指定 getUser 方法发起的是一个 HTTP GET 请求,请求路径为 "users/{id}"。

@Path("id"): 这是一个注解,用于将方法参数的值替换到 URL 路径中的占位符。

Call<User>: 表示方法的返回值类型为 Call<User>
Call<User> 是 Retrofit 库中的一个接口,用于表示一个待执行的网络请求,并指定响应数据的类型为 User。
 */
interface MyApiService {
    // 定义一个获取用户信息的 GET 请求,{id} 表示动态参数
    @GET("users/{id}")

    //作用:定义一个 getUser 方法,该方法接收一个 userId 参数,用于替换 URL 路径中的 {id} 占位符
    // 并返回一个 Call<User> 对象,用于发起网络请求并获取 User 信息。
    fun getUser(@Path("id") userId: Int): Call<User>
}

/*
流程:
使用 Retrofit 库创建一个 MyApiService 接口的实现类。
调用 getUser 方法,并传入一个用户 ID。
Retrofit 库会将用户 ID 替换到 URL 路径中的 {id} 占位符,生成完整的 URL。
Retrofit 库会发起一个 HTTP GET 请求,请求该 URL。
服务器会返回一个包含用户信息的 JSON 数据。
Retrofit 库会将 JSON 数据转换为一个 User 对象。
getUser 方法会返回一个 Call<User> 对象,该对象包含了 User 对象。
你可以通过调用 Call<User> 对象的 enqueue 方法,异步地执行网络请求,并在回调函数中处理响应数据。



调用 getUser 方法,并传入一个用户 ID。   传用户ID是干什么?
指定请求目标

getUser(userId: Int) 方法中的 userId 参数用于指定要获取哪个用户的信息。
这个 userId 会被 @Path("id") 注解绑定到 URL 路径中的 {id} 占位符。
例如,如果你调用 getUser(123)
那么 Retrofit 实际请求的 URL 就会是 https://api.example.com/users/123(假设 BASE_URL 为 https://api.example.com/)。
RESTful API 设计原则

RESTful API 倾向于使用 URL 来标识资源。
在获取单个资源时,通常会将资源的 ID 放在 URL 路径中。
通过这种方式,服务器可以根据 URL 中的 ID 找到对应的用户数据,并将其返回给客户端。
服务器端的处理

当服务器接收到 https://api.example.com/users/123 这个请求时,它会解析 URL 路径中的 123 这个 ID。
服务器会根据这个 ID 从数据库或其他数据源中查询对应的用户信息。
如果找到了对应的用户,服务器会将用户信息封装成 JSON 格式的数据,并将其返回给客户端。
如果找不到对应的用户,服务器可能会返回一个 404 Not Found 错误。



"HTTP GET 请求" 是指客户端(例如你的 Android 应用)向服务器请求特定资源的一种方式,它基于 HTTP 协议。
1. HTTP 方法:GET
GET 是 HTTP 协议中定义的一种请求方法(也称为动词)。
GET 方法用于从服务器请求指定的资源。
GET 请求通常用于获取数据,而不是修改数据。

2. 请求过程
客户端创建一个 HTTP GET 请求,其中包含要请求的资源的 URL。
客户端将请求发送到服务器。
服务器接收到请求后,会根据 URL 查找对应的资源。
如果找到了资源,服务器会将资源的内容封装到 HTTP 响应中,并将其发送回客户端。
如果找不到资源,服务器会返回一个错误响应(例如 404 Not Found)。


Call<User>
1. Call 接口
Call 是 Retrofit 库中的一个核心接口。
它代表一个可以被执行的 HTTP 请求。
Call 接口定义了一些方法,例如 execute()(同步执行请求)和 enqueue()(异步执行请求),用于发起网络请求并获取响应数据。

2. 泛型 <User>
Call<User> 是一个泛型类型。
User 是泛型参数,表示响应数据的类型。
这意味着 Retrofit 会尝试将服务器返回的数据转换为 User 对象。
如果服务器返回的数据无法转换为 User 对象,Retrofit 会抛出一个异常。

3. 作用
Call<User> 对象封装了网络请求的所有信息,包括请求的 URL、HTTP 方法、请求头、请求体等。
你可以通过调用 Call<User> 对象的 execute() 或 enqueue() 方法来发起网络请求。
当网络请求成功时,Retrofit 会将服务器返回的数据转换为 User 对象,并将其传递给你的回调函数。
当网络请求失败时,Retrofit 会将错误信息传递给你的回调函数。

泛型(Generics)是一种编程技术,允许你在定义类、接口和方法时使用类型参数,而不是具体的类型
这些类型参数在使用时才被指定为实际的类型。 这样可以编写更通用、更灵活、类型安全的代码。
 */

在这个接口中:

  • @GET("users/{id}") 定义了一个 GET 请求,请求路径中 {id} 会被 @Path("id") 注解的参数替换。
  • fun getUser(@Path("id") userId: Int): Call<User> 表示获取到的数据将会被反序列化成一个 User 对象,并封装在 Call<User> 中。

四、构建 Retrofit 实例

我们需要构建一个 Retrofit 实例,并创建 API 接口对象。通常我们会做一些全局配置,例如:设置基础 URL 以及注册 JSON 解析转换器。

package com.example.myapplication

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor

object RetrofitClient {
    private const val BASE_URL = "https://api.example.com/"  // 注意最后的斜杠

    // 可选:添加日志拦截器打印请求日志,便于调试

    /*
    HttpLoggingInterceptor() 是 OkHttp 库中提供的一个拦截器,用于记录 HTTP 请求和响应的详细日志。
    当应用发出 HTTP 请求或接收响应时,HttpLoggingInterceptor 会截取这些交互的信息。
    它可以记录请求行、请求头、响应状态码、响应头以及响应体内容。
    对于调试网络请求、分析问题(例如请求格式不正确、服务器返回错误等)非常有帮助。

    HttpLoggingInterceptor 提供几种日志记录级别,可以根据需要进行配置:
    NONE:不记录任何信息。
    BASIC:只记录请求和响应的摘要信息,例如请求方法、URL、响应状态码以及耗时。
    HEADERS:在 BASIC 的基础上,还会记录请求和响应的头信息。
    BODY:记录所有细节,包含请求和响应的全部信息(请求体和响应体)。
    设置为 BODY 级别时,会输出所有数据,这在开发时调试非常有用,但在生产环境中一般不建议开启,以免泄露敏感信息。

    HttpLoggingInterceptor.Level.BODY 是 OkHttp 日志拦截器中的一个日志级别配置
    它表示记录所有 HTTP 请求与响应的细节信息,包括请求和响应的头部信息以及完整的消息体。
     */
    private val loggingInterceptor = HttpLoggingInterceptor().apply {
        level = HttpLoggingInterceptor.Level.BODY
    }

    /*
    OkHttpClient.Builder() 是 OkHttp 库中用于构建 OkHttpClient 实例的一个构造器。

    OkHttpClient 是 OkHttp 库中提供的一个类,用于处理 HTTP 网络请求
    它封装了所有与网络通信相关的逻辑,包括连接管理、请求发送、响应接收、连接池管理和缓存支持等
    通过 OkHttpClient,你可以方便地发起 GET、POST 等各种 HTTP 请求
    并通过它内置的机制对请求进行配置和优化(例如添加拦截器、设置超时时间等)。

    .addInterceptor(loggingInterceptor) 是 OkHttpClient.Builder 的一个方法调用
    用于将一个拦截器(这里是 loggingInterceptor)添加到 OkHttpClient 实例中。
     */
    private val httpClient = OkHttpClient.Builder()
        .addInterceptor(loggingInterceptor)
        .build()

    // 构建 Retrofit 实例
    /*
    构建 Retrofit 实例的主要作用是创建一个用于网络通信的客户端
    通过它可以向服务器发起 HTTP 请求,并将返回的数据转换为我们定义的数据模型
    Retrofit 提供了一种简单、声明式的方式定义 API 接口,然后通过构建的 Retrofit 实例生成相应的实现,从而实现网络请求

    .addConverterFactory(GsonConverterFactory.create()) 是 Retrofit 库中的一个方法调用
    用于添加一个转换器工厂(Converter Factory),它负责将服务器返回的数据转换为应用程序可以使用的 Java 或 Kotlin 对象
    具体来说,GsonConverterFactory.create() 创建了一个使用 Gson 库进行 JSON 数据转换的转换器工厂。
    
    retrofit.create(MyApiService::class.java) 的作用是根据你定义的 API 接口生成一个实现类实例
    使得你可以方便地发起网络请求并获取响应数据。
     */
    val instance: MyApiService by lazy {
        val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(httpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        retrofit.create(MyApiService::class.java)
    }
}

上面的代码中,我们:

  • 定义了一个 RetrofitClient 对象,里面配置了基础 URL、OkHttp 客户端和 Gson JSON 转换器;
  • 使用 Retrofit.Builder() 构建 Retrofit 实例,并调用 create() 方法生成 MyApiService 接口的实现。

五、调用 API 接口

在 Activity 或其他类中调用 API 接口,通过 Retrofit 进行网络请求。Retrofit 提供两种方式:同步调用(execute())和异步调用(enqueue())。下面我们展示如何在 Android 中使用异步调用并在主线程中更新 UI。

package com.example.myapplication

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.IOException

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 假设当前布局文件为 activity_main.xml
        setContentView(R.layout.activity_main)

        // 示例:请求 id 为 1 的用户信息

        /*
        .enqueue(): 是 Call 接口的一个方法,用于异步执行网络请求。异步请求不会阻塞主线程(UI 线程),避免应用卡顿。
        
        object : Callback<User> { ... }: 创建一个匿名对象,实现 Callback<User> 接口
            Callback 接口用于处理异步请求的结果。User 是期望的响应数据类型。
            
        
         */
        RetrofitClient.instance.getUser(1).enqueue(object : Callback<User> {
            override fun onResponse(call: Call<User>, response: Response<User>) {
                if (response.isSuccessful) {
                    // 获取服务器返回的 User 对象数据
                    response.body()?.let { user ->
                        // 在主线程中更新 UI
                        runOnUiThread {
                            Toast.makeText(
                                this@MainActivity,
                                "请求成功:${user.name}",
                                Toast.LENGTH_LONG
                            ).show()
                        }
                        Log.d("MainActivity", "User Info: $user")
                    } ?: run {
                        // 如果 response.body() 返回 null,则说明响应内容为空
                        onFailure(call, IOException("Empty response body"))
                    }
                } else {
                    // 响应不成功,可根据 response.errorBody() 做进一步处理
                    onFailure(call, IOException("Error response: ${response.code()}"))
                }
            }

            override fun onFailure(call: Call<User>, t: Throwable) {
                // 请求失败。这里可以在主线程中操作UI,比如弹.Toast消息
                runOnUiThread {
                    Toast.makeText(
                        this@MainActivity,
                        "请求失败:${t.message}",
                        Toast.LENGTH_LONG
                    ).show()
                }
                Log.d("MainActivity", "Error: ${t.message}")
            }
        })
    }
}

在上面的例子中,我们:

  • 调用 RetrofitClient.instance.getUser(1) 获取一个 Call<User> 对象;
  • 使用 enqueue() 异步发送请求,并设置 onResponse 和 onFailure 两个回调。
  • 在 onResponse 方法中,检查请求是否成功,若成功则通过 response.body() 获取到 User 对象,并更新 UI(记得需要切换到主线程更新 UI,使用 runOnUiThread)。
  • 在 onFailure 方法中,处理请求失败,比如显示错误提示或进行日志记录。

六、总结

通过上面的示例,我们了解了 Retrofit 的基本用法,主要包括:

  1. 添加 Retrofit 和相关依赖。
  2. 定义数据模型和 API 接口,用注解标明 HTTP 请求方法及参数。
  3. 构建 Retrofit 实例,并配置基础 URL、OkHttp 客户端和转换器。
  4. 调用 API 接口进行网络请求,并通过异步回调处理请求结果。
  5. 在请求成功时更新 UI、处理响应数据,在请求失败时进行错误处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值