Kotlin实现Retrofit风格的网络请求封装

1. 添加依赖

确保在 build.gradle 文件中添加了必要的依赖:

gradle 复制代码
dependencies {
    // Retrofit
    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.3'

    // Kotlin Coroutines
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'

    // Lifecycle (用于协程的 lifecycleScope)
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
}

2. 定义数据模型

定义数据模型类,例如 User

kotlin 复制代码
data class User(
    val id: Int,
    val name: String,
    val email: String
)

3. 定义 API 接口

使用 Retrofit 的注解定义 API 接口:

kotlin 复制代码
interface ApiService {
    @GET("users/{id}")
    suspend fun getUser(@Path("id") userId: Int): Response<User>

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

    @POST("refresh_token")
    suspend fun refreshToken(): Response<TokenResponse>
}

4. 创建 Retrofit 实例

创建 Retrofit 实例并配置它,包括日志拦截器、失败重试拦截器和 Token 刷新拦截器:

kotlin 复制代码
object RetrofitClient {
    private const val BASE_URL = "https://api.example.com/"
    private const val MAX_RETRIES = 3

    val apiService: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient())
            .build()
            .create(ApiService::class.java)
    }

    private fun okHttpClient(): OkHttpClient {
        val loggingInterceptor = HttpLoggingInterceptor()
        loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY

        val retryInterceptor = RetryInterceptor(MAX_RETRIES)

        val tokenRefreshInterceptor = TokenRefreshInterceptor()

        return OkHttpClient.Builder()
            .addInterceptor(loggingInterceptor)
            .addInterceptor(retryInterceptor)
            .addInterceptor(tokenRefreshInterceptor)
            .build()
    }
}

5. 实现拦截器

5.1 日志拦截器

日志拦截器已经通过 HttpLoggingInterceptor 实现。

5.2 失败重试拦截器

实现一个失败重试拦截器:

kotlin 复制代码
class RetryInterceptor(private val maxRetries: Int) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        var retries = 0
        var request = chain.request()
        var response: Response? = null

        while (retries < maxRetries) {
            try {
                response = chain.proceed(request)
                if (response.isSuccessful) {
                    return response
                }
            } catch (e: IOException) {
                // Log the exception
            }
            retries++
        }
        return response ?: throw IOException("Failed to retry request")
    }
}
5.3 Token 刷新拦截器

实现一个 Token 刷新拦截器:

kotlin 复制代码
class TokenRefreshInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val response = chain.proceed(request)

        if (response.code == 401) { // Token 失效
            val refreshTokenResponse = RetrofitClient.apiService.refreshToken()
            if (refreshTokenResponse.isSuccessful) {
                val newToken = refreshTokenResponse.body()?.token
                if (newToken != null) {
                    // 更新 Token
                    // 重新发送请求
                    val newRequest = request.newBuilder()
                        .header("Authorization", "Bearer $newToken")
                        .build()
                    return chain.proceed(newRequest)
                }
            }
        }
        return response
    }
}

6. 封装网络请求

封装网络请求逻辑,使用协程和 Flow:

kotlin 复制代码
import kotlinx.coroutines.flow.flow
import retrofit2.Response

object NetworkRepository {
    suspend fun fetchUser(userId: Int) = RetrofitClient.apiService.getUser(userId)

    suspend fun fetchUsers() = RetrofitClient.apiService.getUsers()
}

7. 在 ViewModel 中使用封装的网络请求

在 ViewModel 中调用封装的网络请求,并使用 StateFlowLiveData 管理状态:

kotlin 复制代码
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.*

class MainViewModel : ViewModel() {
    private val _networkState = MutableStateFlow<NetworkState<List<User>>>(NetworkState.Loading())
    val networkState = _networkState.asLiveData()

    init {
        fetchUsers()
    }

    private fun fetchUsers() {
        viewModelScope.launch {
            _networkState.value = NetworkState.Loading()
            try {
                val response = NetworkRepository.fetchUsers()
                if (response.isSuccessful) {
                    _networkState.value = NetworkState.Success(response.body()!!)
                } else {
                    _networkState.value = NetworkState.Error(Exception("Error: ${response.code()}"))
                }
            } catch (e: Exception) {
                _networkState.value = NetworkState.Error(e)
            }
        }
    }
}

8. 在 Activity 或 Fragment 中观察数据

在 Activity 或 Fragment 中观察 ViewModel 中的数据,并更新 UI:

kotlin 复制代码
class MainActivity : AppCompatActivity() {
    private val viewModel: MainViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        viewModel.networkState.observe(this) { state ->
            when (state) {
                is NetworkState.Loading -> {
                    // Show loading
                }
                is NetworkState.Success -> {
                    // Update UI with users
                }
                is NetworkState.Error -> {
                    // Show error
                }
            }
        }
    }
}

9. 错误处理和加载状态管理

可以进一步封装错误处理和加载状态管理,例如使用密封类来表示网络请求的状态:

kotlin 复制代码
sealed class NetworkState<out T : Any> {
    class Loading<out T : Any> : NetworkState<T>()
    data class Success<out T : Any>(val data: T) : NetworkState<T>()
    data class Error<out T : Any>(val exception: Exception) : NetworkState<T>()
}

通过以上步骤,你可以实现一个高效、简洁且易于维护的 Retrofit 风格的网络请求封装,结合协程和 Flow,使得网络请求的代码更加优雅。

相关推荐
alexhilton1 天前
使用FunctionGemma进行设备端函数调用
android·kotlin·android jetpack
lhDream1 天前
Kotlin 开发者必看!JetBrains 开源 LLM 框架 Koog 快速上手指南(含示例)
kotlin
RdoZam2 天前
Android-封装基类Activity\Fragment,从0到1记录
android·kotlin
Kapaseker2 天前
研究表明,开发者对Kotlin集合的了解不到 20%
android·kotlin
DianSan_ERP2 天前
电商API接口全链路监控:构建坚不可摧的线上运维防线
大数据·运维·网络·人工智能·git·servlet
呉師傅2 天前
火狐浏览器报错配置文件缺失如何解决#操作技巧#
运维·网络·windows·电脑
糖猫猫cc2 天前
Kite:两种方式实现动态表名
java·kotlin·orm·kite
2501_946205522 天前
晶圆机器人双臂怎么选型?适配2-12寸晶圆的末端效应器有哪些?
服务器·网络·机器人
linux kernel2 天前
第七部分:高级IO
服务器·网络
数字护盾(和中)2 天前
BAS+ATT&CK:企业主动防御的黄金组合
服务器·网络·数据库