Retrofit入门教程

教程来自Claude问答:

请给我开源库Retrofit的使用教程,按从入门到精通的方式由浅入深的给我讲解,并给予相应的示例代码方便理解,请使用Kotlin语言。

好的!下面我将为你提供一份从入门到精通的 Retrofit 完整教程。


第一章:入门基础 --- 什么是 Retrofit?

Retrofit 是 Square 公司开源的一个 Android/Java 类型安全的 HTTP 客户端库 。它将 HTTP API 定义为 Kotlin 接口,并通过注解和动态代理自动生成实现代码,极大简化网络请求逻辑。下面我们先用一张架构图建立整体认知。

1.1 添加依赖

build.gradle.kts(Kotlin DSL)中添加:

kotlin

kotlin 复制代码
dependencies {
    // Retrofit 核心
    implementation("com.squareup.retrofit2:retrofit:2.11.0")
    
    // JSON 转换器(Gson / Moshi / kotlinx.serialization 三选一)
    implementation("com.squareup.retrofit2:converter-gson:2.11.0")
    // 或 Moshi(更推荐 Kotlin 项目)
    implementation("com.squareup.retrofit2:converter-moshi:2.11.0")
    
    // Kotlin 协程支持
    implementation("com.squareup.retrofit2:adapter-rxjava3:2.11.0") // RxJava(可选)
    
    // OkHttp 日志拦截器(调试用)
    implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
}

别忘了 AndroidManifest 中声明网络权限:

xml

xml 复制代码
<uses-permission android:name="android.permission.INTERNET" />

第二章:核心用法 --- 定义 API 接口

2.1 创建数据模型

kotlin

kotlin 复制代码
// 数据类自动映射 JSON 字段
data class User(
    val id: Int,
    val name: String,
    val email: String,
    val username: String
)

data class Post(
    val id: Int,
    val userId: Int,
    val title: String,
    val body: String
)

// 创建 POST 请求时的请求体
data class CreatePostRequest(
    val title: String,
    val body: String,
    val userId: Int
)

2.2 定义 API 接口(核心概念)

kotlin

kotlin 复制代码
import retrofit2.http.*
import retrofit2.Call
import retrofit2.Response

interface ApiService {
    
    // ─── GET 请求 ──────────────────────────────────
    
    // 获取用户列表
    @GET("users")
    fun getUsers(): Call<List<User>>
    
    // 路径参数:{id} 对应 @Path("id")
    @GET("users/{id}")
    fun getUserById(@Path("id") userId: Int): Call<User>
    
    // 查询参数:?_page=1&_limit=10
    @GET("posts")
    fun getPosts(
        @Query("_page") page: Int,
        @Query("_limit") limit: Int
    ): Call<List<Post>>
    
    // 多个查询参数 Map
    @GET("posts")
    fun searchPosts(@QueryMap params: Map<String, String>): Call<List<Post>>
    
    // ─── POST 请求 ─────────────────────────────────
    
    // 请求体(JSON)
    @POST("posts")
    fun createPost(@Body request: CreatePostRequest): Call<Post>
    
    // 表单提交
    @FormUrlEncoded
    @POST("login")
    fun login(
        @Field("username") username: String,
        @Field("password") password: String
    ): Call<User>
    
    // ─── PUT / PATCH / DELETE ──────────────────────
    
    @PUT("posts/{id}")
    fun updatePost(
        @Path("id") postId: Int,
        @Body post: Post
    ): Call<Post>
    
    @PATCH("posts/{id}")
    fun patchPost(
        @Path("id") postId: Int,
        @Body fields: Map<String, String>
    ): Call<Post>
    
    @DELETE("posts/{id}")
    fun deletePost(@Path("id") postId: Int): Call<Response<Unit>>
    
    // ─── 自定义请求头 ──────────────────────────────
    
    @Headers("Cache-Control: max-age=640000")
    @GET("users")
    fun getUsersWithCache(): Call<List<User>>
    
    // 动态 Header
    @GET("protected/data")
    fun getProtectedData(@Header("Authorization") token: String): Call<String>
}

2.3 创建 Retrofit 实例

kotlin

kotlin 复制代码
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitClient {
    
    private const val BASE_URL = "https://jsonplaceholder.typicode.com/"
    
    // OkHttp 日志拦截器(仅 Debug 模式开启)
    private val loggingInterceptor = HttpLoggingInterceptor().apply {
        level = HttpLoggingInterceptor.Level.BODY
    }
    
    private val okHttpClient = OkHttpClient.Builder()
        .addInterceptor(loggingInterceptor)
        .connectTimeout(30, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .build()
    
    private val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    
    // 懒加载单例
    val apiService: ApiService by lazy {
        retrofit.create(ApiService::class.java)
    }
}

2.4 发起同步 / 异步请求

kotlin

kotlin 复制代码
class MainActivity : AppCompatActivity() {
    
    private val api = RetrofitClient.apiService
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // ── 异步请求(推荐)──────────────────────────
        api.getUsers().enqueue(object : Callback<List<User>> {
            override fun onResponse(call: Call<List<User>>, response: Response<List<User>>) {
                if (response.isSuccessful) {
                    val users = response.body()
                    // response.code() == 200
                    // response.headers() 获取响应头
                    users?.forEach { println(it.name) }
                } else {
                    // 处理 HTTP 错误(4xx / 5xx)
                    val errorBody = response.errorBody()?.string()
                    println("Error ${response.code()}: $errorBody")
                }
            }
            
            override fun onFailure(call: Call<List<User>>, t: Throwable) {
                // 网络错误、超时等
                println("Network Error: ${t.message}")
            }
        })
        
        // ── 同步请求(不能在主线程)─────────────────
        Thread {
            try {
                val response = api.getUserById(1).execute()
                if (response.isSuccessful) {
                    println(response.body()?.name)
                }
            } catch (e: IOException) {
                println("IO Error: ${e.message}")
            }
        }.start()
    }
}

第三章:进阶功能

3.1 OkHttp 拦截器

拦截器是 Retrofit 最强大的扩展点,可以统一处理 Token、加密、日志等。

kotlin

kotlin 复制代码
// ── 认证拦截器:自动添加 Authorization Header ──
class AuthInterceptor(private val tokenProvider: () -> String) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
        
        val authenticatedRequest = originalRequest.newBuilder()
            .header("Authorization", "Bearer ${tokenProvider()}")
            .header("Content-Type", "application/json")
            .build()
        
        return chain.proceed(authenticatedRequest)
    }
}

// ── Token 刷新拦截器(401 自动续签)──────────────
class TokenRefreshInterceptor : Authenticator {
    override fun authenticate(route: Route?, response: Response): Request? {
        // 如果已经重试过了,放弃
        if (response.request.header("Retry-Token") != null) return null
        
        // 同步刷新 Token(这里简化演示)
        val newToken = refreshTokenSynchronously() ?: return null
        
        return response.request.newBuilder()
            .header("Authorization", "Bearer $newToken")
            .header("Retry-Token", "true")
            .build()
    }
    
    private fun refreshTokenSynchronously(): String? {
        // 实际项目中调用刷新接口
        return "new_access_token"
    }
}

// ── 构建带拦截器的 OkHttpClient ──────────────────
val client = OkHttpClient.Builder()
    .addInterceptor(AuthInterceptor { UserPrefs.getToken() })
    .authenticator(TokenRefreshInterceptor())
    .addInterceptor(HttpLoggingInterceptor().apply {
        level = if (BuildConfig.DEBUG) {
            HttpLoggingInterceptor.Level.BODY
        } else {
            HttpLoggingInterceptor.Level.NONE
        }
    })
    .build()

3.2 文件上传(Multipart)

kotlin

kotlin 复制代码
interface FileUploadService {
    
    // 单文件上传
    @Multipart
    @POST("upload")
    fun uploadFile(
        @Part file: MultipartBody.Part,
        @Part("description") description: RequestBody
    ): Call<UploadResponse>
    
    // 多文件上传
    @Multipart
    @POST("upload/multiple")
    fun uploadMultipleFiles(
        @PartMap parts: Map<String, @JvmSuppressWildcards RequestBody>
    ): Call<UploadResponse>
}

// 使用示例
fun uploadImage(filePath: String) {
    val file = File(filePath)
    
    // 构建 RequestBody
    val requestFile = file.asRequestBody("image/jpeg".toMediaTypeOrNull())
    
    // 构建 MultipartBody.Part,"file" 是后端接收的字段名
    val body = MultipartBody.Part.createFormData("file", file.name, requestFile)
    
    // 描述信息
    val description = "My upload".toRequestBody("text/plain".toMediaTypeOrNull())
    
    RetrofitClient.apiService.uploadFile(body, description)
        .enqueue(object : Callback<UploadResponse> {
            override fun onResponse(...) { /* 处理结果 */ }
            override fun onFailure(...) { /* 处理错误 */ }
        })
}

3.3 下载文件(Streaming)

kotlin

kotlin 复制代码
interface DownloadService {
    // @Streaming 阻止 Retrofit 将整个文件读入内存
    @Streaming
    @GET
    fun downloadFile(@Url fileUrl: String): Call<ResponseBody>
}

// 将 ResponseBody 写入磁盘
fun saveFile(body: ResponseBody, savePath: String): Boolean {
    return try {
        val file = File(savePath)
        body.byteStream().use { inputStream ->
            file.outputStream().use { outputStream ->
                inputStream.copyTo(outputStream)
            }
        }
        true
    } catch (e: IOException) {
        false
    }
}

第四章:Kotlin 协程集成(现代推荐方式)

这是目前 Android 开发最推荐的方式,搭配 ViewModel + 协程效果最佳。

4.1 suspend 函数接口定义

kotlin

kotlin 复制代码
// Retrofit 原生支持 suspend 函数,无需额外 Adapter
interface CoroutineApiService {
    
    // 直接返回数据(失败时抛异常)
    @GET("users")
    suspend fun getUsers(): List<User>
    
    // 返回 Response<T> 可以获取状态码、Header 等
    @GET("users/{id}")
    suspend fun getUserById(@Path("id") id: Int): Response<User>
    
    @POST("posts")
    suspend fun createPost(@Body request: CreatePostRequest): Post
    
    @DELETE("posts/{id}")
    suspend fun deletePost(@Path("id") id: Int): Response<Unit>
}

4.2 在 ViewModel 中使用

kotlin

kotlin 复制代码
class UserViewModel(
    private val api: CoroutineApiService = RetrofitClient.coroutineApiService
) : ViewModel() {
    
    private val _uiState = MutableStateFlow<UiState<List<User>>>(UiState.Loading)
    val uiState: StateFlow<UiState<List<User>>> = _uiState.asStateFlow()
    
    fun loadUsers() {
        viewModelScope.launch {
            _uiState.value = UiState.Loading
            
            _uiState.value = try {
                val users = api.getUsers()  // IO 在 Retrofit 内部处理
                UiState.Success(users)
            } catch (e: HttpException) {
                // HTTP 错误(4xx, 5xx)
                UiState.Error("Server error: ${e.code()}")
            } catch (e: IOException) {
                // 网络问题(无连接、超时)
                UiState.Error("Network error: ${e.message}")
            }
        }
    }
}

// 通用 UI 状态封装
sealed class UiState<out T> {
    object Loading : UiState<Nothing>()
    data class Success<T>(val data: T) : UiState<T>()
    data class Error(val message: String) : UiState<Nothing>()
}

4.3 在 Activity/Fragment 中收集状态

kotlin

kotlin 复制代码
class UserFragment : Fragment() {
    
    private val viewModel: UserViewModel by viewModels()
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        viewModel.loadUsers()
        
        // 收集 StateFlow
        viewLifecycleOwner.lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect { state ->
                    when (state) {
                        is UiState.Loading  -> showLoading()
                        is UiState.Success  -> showUsers(state.data)
                        is UiState.Error    -> showError(state.message)
                    }
                }
            }
        }
    }
}

第五章:最佳实践 --- Repository 封装模式

5.1 统一错误处理封装

kotlin

kotlin 复制代码
// 网络请求结果封装
sealed class NetworkResult<out T> {
    data class Success<T>(val data: T) : NetworkResult<T>()
    data class Error(val code: Int, val message: String) : NetworkResult<Nothing>()
    object Loading : NetworkResult<Nothing>()
}

// 扩展函数:安全执行网络请求
suspend fun <T> safeApiCall(apiCall: suspend () -> T): NetworkResult<T> {
    return try {
        NetworkResult.Success(apiCall.invoke())
    } catch (e: HttpException) {
        NetworkResult.Error(e.code(), e.message())
    } catch (e: IOException) {
        NetworkResult.Error(-1, "Network unavailable: ${e.message}")
    } catch (e: Exception) {
        NetworkResult.Error(-2, "Unknown error: ${e.message}")
    }
}

5.2 Repository 层

kotlin

kotlin 复制代码
class UserRepository(private val api: CoroutineApiService) {
    
    suspend fun getUsers(): NetworkResult<List<User>> = safeApiCall {
        api.getUsers()
    }
    
    suspend fun getUserById(id: Int): NetworkResult<User> = safeApiCall {
        val response = api.getUserById(id)
        if (response.isSuccessful) {
            response.body() ?: throw HttpException(response)
        } else {
            throw HttpException(response)
        }
    }
    
    suspend fun createPost(title: String, body: String): NetworkResult<Post> = safeApiCall {
        api.createPost(CreatePostRequest(title, body, userId = 1))
    }
}

第六章:高级技巧

6.1 动态 BaseUrl

kotlin

kotlin 复制代码
// 接口中使用 @Url 覆盖 baseUrl
interface DynamicUrlService {
    @GET
    suspend fun fetchFromAbsoluteUrl(@Url absoluteUrl: String): ResponseBody
}

// 调用时传入完整 URL
api.fetchFromAbsoluteUrl("https://another-api.com/data/endpoint")

6.2 自定义 CallAdapter(Flow 支持)

kotlin

kotlin 复制代码
// 让 Retrofit 直接返回 Flow<T>
// 依赖:com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter
// 或自己实现,更简洁的做法是在 Repository 用 flow { emit(safeApiCall{...}) }

fun <T> networkFlow(call: suspend () -> T): Flow<NetworkResult<T>> = flow {
    emit(NetworkResult.Loading)
    emit(safeApiCall { call() })
}.flowOn(Dispatchers.IO)

// ViewModel 中使用
val usersFlow: Flow<NetworkResult<List<User>>> = networkFlow { api.getUsers() }

6.3 请求缓存策略

kotlin

kotlin 复制代码
// 配置 OkHttp Cache
val cacheDir = File(context.cacheDir, "http_cache")
val cache = Cache(cacheDir, 10L * 1024 * 1024) // 10 MB

val client = OkHttpClient.Builder()
    .cache(cache)
    .addNetworkInterceptor { chain ->
        // 网络响应:缓存 60 秒
        val response = chain.proceed(chain.request())
        response.newBuilder()
            .header("Cache-Control", "public, max-age=60")
            .build()
    }
    .addInterceptor { chain ->
        var request = chain.request()
        // 无网络时使用缓存(最长 7 天)
        if (!isNetworkAvailable(context)) {
            request = request.newBuilder()
                .header("Cache-Control", "public, only-if-cached, max-stale=${7 * 24 * 3600}")
                .build()
        }
        chain.proceed(request)
    }
    .build()

6.4 使用 kotlinx.serialization(Kotlin 原生)

kotlin

kotlin 复制代码
// 依赖
// implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
// implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")

@Serializable
data class User(
    val id: Int,
    val name: String,
    val email: String
)

val contentType = "application/json".toMediaType()
val retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(Json.asConverterFactory(contentType))
    .build()

学习路线总结


关键知识点速查

注解 作用 示例
@GET / @POST / @PUT / @DELETE 请求方法 @GET("users")
@Path URL 路径参数 @Path("id") id: Int
@Query URL 查询参数 @Query("page") page: Int
@Body 请求体 @Body user: User
@Header 动态请求头 @Header("Token") token: String
@Multipart + @Part 文件上传 见第三章
@Streaming 流式下载 防止大文件 OOM
@Url 动态 URL 覆盖 baseUrl

Retrofit 的精髓在于注解,下面是所有常用注解的对照表:

最核心的建议 :在现代 Android 项目中,请务必使用 suspend 函数 + ViewModel + Repository 这套组合,配合 Hilt 做依赖注入,这是 2024 年 Android 官方推荐的标准架构。如果需要深入某个具体环节(比如 MockWebServer 单元测试、与 Paging3 结合分页加载、或 Hilt 集成),随时告诉我!

相关推荐
有位神秘人1 天前
Android中Mvvm+Retrofit的常用网络架构记录
android·网络·retrofit
符哥20089 天前
基于 OkHttp+Retrofit 实现 JSON / 表单 / XML/Protobuf 数据格式全解析
okhttp·json·retrofit
CBgPxXIID2 个月前
基于国产M0核MCU平台的风机量产程序与FOC电机控制开发方案:含龙博格电机观测器与多种功能源码
retrofit
鸟儿不吃草2 个月前
android的Retrofit请求https://192.168.43.73:8080/报错:Handshake failed
android·retrofit
猿小羽2 个月前
OkHttp vs Retrofit 技术分析报告 - 1769404939594
http·okhttp·retrofit·csdn
灵感菇_2 个月前
全面解析 Retrofit 网络框架
android·kotlin·网络请求·retrofit
fanruitian3 个月前
SpringBoot 集成retrofit httpclient
java·spring boot·retrofit
安果移不动3 个月前
Android 架构进化之路:为何在 Retrofit + 协程重构中,我们需要引入 Hilt?
android·架构·retrofit
咨询QQ180809513 个月前
双闭环Vienna整流器SVPWM控制:大功率直流800V以上MATLAB Simulink仿...
retrofit