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

相关推荐
FreeBuf_21 小时前
思科CCX软件曝高危RCE:攻击者可利用Java RMI和CCX Editor获取root权限
java·网络·安全
卓应1 天前
路由协议的基础
网络·智能路由器
老蒋新思维1 天前
2025 创客匠人全球创始人 IP + AI 万人高峰论坛:破局创业困境,拥抱无限未来
大数据·网络·人工智能·网络协议·tcp/ip·创客匠人·知识变现
0和1的舞者1 天前
网络通信的奥秘:HTTP详解 (六)
网络·网络协议·计算机网络·http·https·计算机科学与技术
敢敢のwings1 天前
AnyVP*:企业级远程办公SSL深度技术解析
网络·网络协议·ssl
门思科技1 天前
LoRa 与 LoRaWAN 技术解析:物理层原理、网络架构与典型物联网应用场景
网络·物联网·架构
橘子真甜~1 天前
Linux网络编程 - 1网络编程基础
网络·网络编程基础
shenshizhong1 天前
揭开 kotlin 中协程的神秘面纱
android·kotlin
YisquareTech1 天前
从“零”构建零售EDI能力:实施路径与常见陷阱
网络·人工智能·edi·零售·零售edi
陌路201 天前
Linux32 网络编程TCP通信(缓冲区问题)
服务器·网络·tcp/ip