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,使得网络请求的代码更加优雅。

相关推荐
6666v617 小时前
Android Kotlin(2) 协程上下文与异常处理机制
kotlin
北邮刘老师17 小时前
【智能体互联协议解析】身份码-智能体的身份证号
网络·人工智能·大模型·智能体·智能体互联网
日更嵌入式的打工仔19 小时前
Ethercat COE 笔记
网络·笔记·ethercat
UVM_ERROR20 小时前
UVM实战:RDMA Host侧激励开发全流程问题排查与解决
服务器·网络·数据库
福尔摩斯张20 小时前
插件式架构:解耦与扩展的艺术与实践(超详细)
linux·服务器·网络·网络协议·tcp/ip
老王熬夜敲代码21 小时前
网路编程--协议
linux·网络·笔记
北邮刘老师21 小时前
智能体,超越人类与机器的世界“理解者”
网络·人工智能·大模型·智能体·智能体互联网
zhangphil21 小时前
Kotlin协程await与join挂起函数异同
kotlin
A13247053121 天前
SSH远程连接入门:安全高效地管理服务器
linux·运维·服务器·网络·chrome·github
yenggd1 天前
企业总部-分支-门点-数据中心使用骨干网SRv6 BE互联互通整体架构配置案例
运维·网络·计算机网络·华为·架构