Retrofit #

一、Retrofit概述 #

Retrofit是Square公司开发的类型安全的HTTP客户端,基于OkHttp封装,通过注解定义API接口,使网络请求更加简洁。

1.1 Retrofit特点 #

  • 类型安全
  • 注解定义API
  • 支持多种数据格式
  • 支持协程
  • 支持RxJava

1.2 添加依赖 #

kotlin
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.12.0")
}

二、基本使用 #

2.1 定义API接口 #

kotlin
interface ApiService {
    
    @GET("users")
    suspend fun getUsers(): List<User>
    
    @GET("users/{id}")
    suspend fun getUserById(@Path("id") id: Int): User
    
    @GET("users")
    suspend fun searchUsers(@Query("name") name: String): List<User>
    
    @POST("users")
    suspend fun createUser(@Body user: User): User
    
    @PUT("users/{id}")
    suspend fun updateUser(@Path("id") id: Int, @Body user: User): User
    
    @DELETE("users/{id}")
    suspend fun deleteUser(@Path("id") id: Int): Response<Unit>
}

2.2 创建Retrofit实例 #

kotlin
object RetrofitClient {
    
    private const val BASE_URL = "https://api.example.com/"
    
    private val loggingInterceptor = HttpLoggingInterceptor().apply {
        level = HttpLoggingInterceptor.Level.BODY
    }
    
    private val okHttpClient = OkHttpClient.Builder()
        .addInterceptor(loggingInterceptor)
        .connectTimeout(30, TimeUnit.SECONDS)
        .build()
    
    val apiService: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}

2.3 使用API #

kotlin
class MainViewModel : ViewModel() {
    
    private val apiService = RetrofitClient.apiService
    
    private val _users = MutableLiveData<List<User>>()
    val users: LiveData<List<User>> = _users
    
    private val _error = MutableLiveData<String>()
    val error: LiveData<String> = _error
    
    fun loadUsers() {
        viewModelScope.launch {
            try {
                val result = apiService.getUsers()
                _users.value = result
            } catch (e: Exception) {
                _error.value = e.message
            }
        }
    }
    
    fun searchUsers(name: String) {
        viewModelScope.launch {
            try {
                val result = apiService.searchUsers(name)
                _users.value = result
            } catch (e: Exception) {
                _error.value = e.message
            }
        }
    }
}

三、请求注解 #

3.1 HTTP方法注解 #

注解 说明
@GET GET请求
@POST POST请求
@PUT PUT请求
@DELETE DELETE请求
@PATCH PATCH请求
@HEAD HEAD请求
@HTTP 自定义方法

3.2 参数注解 #

注解 说明 示例
@Path 路径参数 @Path(“id”) id: Int
@Query 查询参数 @Query(“name”) name: String
@QueryMap 查询参数Map @QueryMap params: Map<String, String>
@Body 请求体 @Body user: User
@Field 表单字段 @Field(“name”) name: String
@FieldMap 表单字段Map @FieldMap fields: Map<String, String>
@Header 请求头 @Header(“Authorization”) token: String
@HeaderMap 请求头Map @HeaderMap headers: Map<String, String>

3.3 示例 #

kotlin
interface ApiService {
    
    // 路径参数
    @GET("users/{id}/posts/{postId}")
    suspend fun getPost(@Path("id") userId: Int, @Path("postId") postId: Int): Post
    
    // 查询参数
    @GET("users")
    suspend fun getUsers(
        @Query("page") page: Int,
        @Query("size") size: Int,
        @Query("sort") sort: String? = null
    ): List<User>
    
    // 查询参数Map
    @GET("users")
    suspend fun searchUsers(@QueryMap params: Map<String, String>): List<User>
    
    // 请求体
    @POST("users")
    suspend fun createUser(@Body user: User): User
    
    // 表单提交
    @FormUrlEncoded
    @POST("login")
    suspend fun login(
        @Field("username") username: String,
        @Field("password") password: String
    ): LoginResponse
    
    // 请求头
    @GET("users")
    suspend fun getUsers(
        @Header("Authorization") token: String,
        @Header("Accept-Language") language: String
    ): List<User>
    
    // 动态URL
    @GET
    suspend fun getFromUrl(@Url url: String): ResponseBody
}

四、响应处理 #

4.1 Response包装 #

kotlin
@GET("users/{id}")
suspend fun getUser(@Path("id") id: Int): Response<User>

// 使用
val response = apiService.getUser(1)
if (response.isSuccessful) {
    val user = response.body()
} else {
    val errorBody = response.errorBody()?.string()
}

4.2 自定义响应类 #

kotlin
data class ApiResponse<T>(
    val code: Int,
    val message: String,
    val data: T?
)

@GET("users")
suspend fun getUsers(): ApiResponse<List<User>>

五、拦截器 #

5.1 认证拦截器 #

kotlin
class AuthInterceptor(private val tokenProvider: () -> String?) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request().newBuilder()
        
        tokenProvider()?.let { token ->
            request.addHeader("Authorization", "Bearer $token")
        }
        
        return chain.proceed(request.build())
    }
}

// 使用
val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(AuthInterceptor { tokenManager.getToken() })
    .build()

5.2 错误处理拦截器 #

kotlin
class ErrorInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val response = chain.proceed(chain.request())
        
        if (!response.isSuccessful) {
            when (response.code) {
                401 -> throw UnauthorizedException()
                403 -> throw ForbiddenException()
                404 -> throw NotFoundException()
                500 -> throw ServerException()
            }
        }
        
        return response
    }
}

六、数据转换器 #

6.1 Gson转换器 #

kotlin
implementation("com.squareup.retrofit2:converter-gson:2.9.0")

val retrofit = Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create())
    .build()

6.2 Moshi转换器 #

kotlin
implementation("com.squareup.retrofit2:converter-moshi:2.9.0")

val retrofit = Retrofit.Builder()
    .addConverterFactory(MoshiConverterFactory.create())
    .build()

6.3 自定义转换器 #

kotlin
class StringConverterFactory : Converter.Factory() {
    override fun responseBodyConverter(
        type: Type,
        annotations: Array<out Annotation>,
        retrofit: Retrofit
    ): Converter<ResponseBody, *>? {
        if (type == String::class.java) {
            return Converter<ResponseBody, String> { body -> body.string() }
        }
        return null
    }
}

七、文件上传下载 #

7.1 文件上传 #

kotlin
interface ApiService {
    
    @Multipart
    @POST("upload")
    suspend fun uploadFile(
        @Part file: MultipartBody.Part,
        @Part("description") description: RequestBody
    ): UploadResponse
}

// 使用
val file = File("/path/to/file.jpg")
val requestFile = file.asRequestBody("image/jpeg".toMediaType())
val body = MultipartBody.Part.createFormData("file", file.name, requestFile)
val description = "Upload".toRequestBody("text/plain".toMediaType())

val response = apiService.uploadFile(body, description)

7.2 文件下载 #

kotlin
interface ApiService {
    
    @Streaming
    @GET("download/{filename}")
    suspend fun downloadFile(@Path("filename") filename: String): ResponseBody
}

// 使用
suspend fun downloadFile(filename: String, destFile: File) {
    val body = apiService.downloadFile(filename)
    
    body.byteStream().use { input ->
        destFile.outputStream().use { output ->
            input.copyTo(output)
        }
    }
}

// 带进度下载
suspend fun downloadWithProgress(
    filename: String,
    destFile: File,
    onProgress: (progress: Int) -> Unit
) {
    val body = apiService.downloadFile(filename)
    val contentLength = body.contentLength()
    var downloaded = 0L
    
    body.byteStream().use { input ->
        destFile.outputStream().use { output ->
            val buffer = ByteArray(4096)
            var read: Int
            
            while (input.read(buffer).also { read = it } != -1) {
                output.write(buffer, 0, read)
                downloaded += read
                
                if (contentLength > 0) {
                    val progress = (downloaded * 100 / contentLength).toInt()
                    onProgress(progress)
                }
            }
        }
    }
}

八、封装网络层 #

8.1 Repository封装 #

kotlin
class UserRepository(private val apiService: ApiService) {
    
    suspend fun getUsers(): Result<List<User>> {
        return try {
            val users = apiService.getUsers()
            Result.success(users)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
    
    suspend fun getUserById(id: Int): Result<User> {
        return try {
            val user = apiService.getUserById(id)
            Result.success(user)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
    
    suspend fun createUser(user: User): Result<User> {
        return try {
            val createdUser = apiService.createUser(user)
            Result.success(createdUser)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
}

8.2 依赖注入 #

kotlin
// 使用Hilt
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    
    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.BODY
            })
            .connectTimeout(30, TimeUnit.SECONDS)
            .build()
    }
    
    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
    
    @Provides
    @Singleton
    fun provideApiService(retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }
}

九、最佳实践 #

9.1 错误处理 #

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>()
    data class Exception(val e: Throwable) : NetworkResult<Nothing>()
}

suspend fun <T> safeApiCall(apiCall: suspend () -> T): NetworkResult<T> {
    return try {
        NetworkResult.Success(apiCall())
    } catch (e: HttpException) {
        NetworkResult.Error(e.code(), e.message())
    } catch (e: IOException) {
        NetworkResult.Exception(e)
    } catch (e: Exception) {
        NetworkResult.Exception(e)
    }
}

9.2 网络状态处理 #

kotlin
class NetworkAwareRepository(
    private val apiService: ApiService,
    private val context: Context
) {
    
    suspend fun <T> safeNetworkCall(apiCall: suspend () -> T): NetworkResult<T> {
        if (!isNetworkAvailable(context)) {
            return NetworkResult.Error(-1, "No network connection")
        }
        return safeApiCall(apiCall)
    }
}

十、总结 #

本章详细介绍了Retrofit:

  1. Retrofit的基本使用
  2. 请求注解的使用
  3. 响应处理
  4. 拦截器配置
  5. 数据转换器
  6. 文件上传下载
  7. 网络层封装
  8. 最佳实践

Retrofit是Android网络请求的最佳实践,配合OkHttp和协程可以高效地处理网络请求。

最后更新:2026-03-26