在Android开发中,结合Kotlin Coroutine和Retrofit可以构建高效、简洁且可维护的网络层。以下是分步骤的实践指南:
一、基础配置
1. 添加依赖
// 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. 创建数据类
data class User(
val id: Int,
val name: String,
val email: String
)
2. 定义API接口
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实例构建
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层封装
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层调用
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. 多请求并行处理
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. 超时与重试
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. 内存缓存示例
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()
}
}
七、关键注意事项
- 线程切换:使用
withContext(Dispatchers.IO)
确保网络请求在IO线程执行 - 异常边界:在Repository层统一处理所有异常,避免ViewModel中过多try-catch
- 生命周期管理:使用
viewModelScope
自动取消协程,防止内存泄漏 - 响应验证:始终检查
response.isSuccessful
和body() != null
- 流量控制:使用
SharedFlow
或StateFlow
暴露数据,替代LiveData
通过以上实践,可以构建出具备以下特性的网络层:
- 完全的协程支持,避免回调地狱
- 清晰的错误处理流程
- 灵活的请求组合能力
- 可扩展的缓存策略
- 完善的线程安全管理
最终实现网络请求与UI的无缝衔接,提升应用性能和用户体验。