Kotlin Coroutine与Retrofit网络层构建指南

在Android开发中,结合Kotlin Coroutine和Retrofit可以构建高效、简洁且可维护的网络层。以下是分步骤的实践指南:


一、基础配置

1. 添加依赖
gradle 复制代码
// build.gradle (Module)
dependencies {
    // Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    
    // Coroutines
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
    
    // Lifecycle (用于ViewModel的协程作用域)
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
}

二、Retrofit接口定义

1. 创建数据类
kotlin 复制代码
data class User(
    val id: Int,
    val name: String,
    val email: String
)
2. 定义API接口
kotlin 复制代码
interface ApiService {
    @GET("users/{id}")
    suspend fun getUser(@Path("id") id: Int): Response<User>  // 直接返回Response对象,便于错误处理

    @POST("users")
    suspend fun createUser(@Body user: User): Response<Unit>
}

三、Retrofit实例构建

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

    private val okHttpClient = OkHttpClient.Builder()
        .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
        .connectTimeout(30, TimeUnit.SECONDS)
        .build()

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

四、协程调用与错误处理

1. Repository层封装
kotlin 复制代码
class UserRepository {
    private val apiService = RetrofitClient.instance

    suspend fun fetchUser(id: Int): Result<User> = try {
        val response = apiService.getUser(id)
        if (response.isSuccessful && response.body() != null) {
            Result.success(response.body()!!)
        } else {
            Result.failure(Exception("API error: ${response.code()}"))
        }
    } catch (e: Exception) {
        Result.failure(e)
    }
}
2. ViewModel层调用
kotlin 复制代码
class UserViewModel : ViewModel() {
    private val repository = UserRepository()
    val userState = MutableStateFlow<UiState<User>>(UiState.Loading)

    fun loadUser(id: Int) {
        viewModelScope.launch {
            userState.value = UiState.Loading
            when (val result = repository.fetchUser(id)) {
                is Result.Success -> userState.value = UiState.Success(result.data)
                is Result.Failure -> userState.value = UiState.Error(result.exception)
            }
        }
    }
}

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

五、高级优化技巧

1. 多请求并行处理
kotlin 复制代码
suspend fun fetchUserAndPosts(userId: Int): Pair<User, List<Post>> = coroutineScope {
    val userDeferred = async { apiService.getUser(userId) }
    val postsDeferred = async { apiService.getPosts(userId) }
    
    val user = userDeferred.await().body()!!
    val posts = postsDeferred.await().body()!!
    user to posts
}
2. 超时与重试
kotlin 复制代码
suspend fun fetchDataWithRetry() {
    try {
        val data = withTimeout(5000) { // 5秒超时
            retry(retries = 3) {       // 自定义重试逻辑
                apiService.getData()
            }
        }
    } catch (e: TimeoutCancellationException) {
        // 处理超时
    }
}

private suspend fun <T> retry(
    retries: Int = 3,
    initialDelay: Long = 1000,
    maxDelay: Long = 16000,
    factor: Double = 2.0,
    block: suspend () -> T
): T {
    var currentDelay = initialDelay
    repeat(retries) {
        try {
            return block()
        } catch (e: Exception) {
            if (it == retries - 1) throw e
            delay(currentDelay)
            currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay)
        }
    }
    throw IllegalStateException("Unreachable")
}

六、缓存策略实现

1. 内存缓存示例
kotlin 复制代码
class CachedUserRepository {
    private val cache = mutableMapOf<Int, User>()
    private val apiService = RetrofitClient.instance

    suspend fun getUser(id: Int): User {
        return cache[id] ?: apiService.getUser(id).body()?.also {
            cache[id] = it
        } ?: throw NoSuchElementException()
    }
}

七、关键注意事项

  1. 线程切换 :使用 withContext(Dispatchers.IO) 确保网络请求在IO线程执行
  2. 异常边界:在Repository层统一处理所有异常,避免ViewModel中过多try-catch
  3. 生命周期管理 :使用viewModelScope自动取消协程,防止内存泄漏
  4. 响应验证 :始终检查response.isSuccessfulbody() != null
  5. 流量控制 :使用SharedFlowStateFlow暴露数据,替代LiveData

通过以上实践,可以构建出具备以下特性的网络层:

  • 完全的协程支持,避免回调地狱
  • 清晰的错误处理流程
  • 灵活的请求组合能力
  • 可扩展的缓存策略
  • 完善的线程安全管理

最终实现网络请求与UI的无缝衔接,提升应用性能和用户体验。

相关推荐
Kapaseker11 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
A0微声z2 天前
Kotlin Multiplatform (KMP) 中使用 Protobuf
kotlin
alexhilton3 天前
使用FunctionGemma进行设备端函数调用
android·kotlin·android jetpack
lhDream3 天前
Kotlin 开发者必看!JetBrains 开源 LLM 框架 Koog 快速上手指南(含示例)
kotlin
RdoZam3 天前
Android-封装基类Activity\Fragment,从0到1记录
android·kotlin
Kapaseker4 天前
研究表明,开发者对Kotlin集合的了解不到 20%
android·kotlin
郑州光合科技余经理4 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
feifeigo1234 天前
matlab画图工具
开发语言·matlab
dustcell.4 天前
haproxy七层代理
java·开发语言·前端
norlan_jame4 天前
C-PHY与D-PHY差异
c语言·开发语言