Kotlin协程网络请求实战详解

协程让网络请求更简单

在 Android 开发中,处理网络请求是家常便饭。以前用回调或者 AsyncTask,代码容易嵌套得乱七八糟,维护起来头疼。自从 Kotlin 协程出现后,异步操作变得像写同步代码一样清晰。

比如你做个天气 App,用户打开页面要加载当前城市气温、湿度、风速。这些数据来自不同接口,传统方式要开多个线程加回调,稍不注意就 ANR。而用协程,几个请求可以并行发出,等待全部返回后再更新 UI,逻辑一目了然。

基本使用:挂起函数发起请求

假设你用 Retrofit + Kotlin 协程封装网络层,接口定义可以直接返回 Deferred<T>Response<T>。下面是一个典型例子:

interface WeatherService {
@GET("weather")
suspend fun getCurrentWeather(@Query("city") city: String): WeatherResponse
}

这个 suspend 关键字就是协程的核心,表示这个函数只能在协程里调用,不会阻塞主线程。

在 ViewModel 中启动协程

实际调用时,通常在 ViewModel 里通过 viewModelScope 启动协程:

class WeatherViewModel(private val service: WeatherService) : ViewModel() {
private val _weatherData = MutableLiveData<WeatherResponse?>()
val weatherData: LiveData<WeatherResponse?> = _weatherData

fun loadWeather(city: String) {
viewModelScope.launch {
try {
val result = service.getCurrentWeather(city)
_weatherData.value = result
} catch (e: Exception) {
// 处理错误,比如显示 Toast
Log.e("Weather", "Request failed", e)
}
}
}
}

这里 launch 启动一个协程,内部直接调用挂起函数。请求完成或出错后自动切回主线程,更新 LiveData,界面随之刷新。

并行请求优化加载速度

如果需要同时拉多个无关数据,比如首页既要天气又要空气质量,可以用 async 并行执行:

fun loadHomeData(city: String) {
viewModelScope.launch {
try {
val weatherDeferred = async { service.getCurrentWeather(city) }
val airQualityDeferred = async { service.getAirQuality(city) }

val weather = weatherDeferred.await()
val airQuality = airQualityDeferred.await()

// 合并结果更新 UI
_homeData.value = HomeData(weather, airQuality)
} catch (e: Exception) {
Log.e("Home", "Load failed", e)
}
}
}

两个请求几乎同时发出,总耗时接近最慢的那个,而不是相加,用户体验自然更好。

异常处理别忘了

网络哪有百分百可靠的。服务器可能 500,网络可能断开,JSON 可能解析失败。协程里的异常默认会崩溃整个程序,所以每个 launch 最好包上 try-catch。更高级的做法是封装统一的异常处理器或使用拦截器。

另外,用户退出页面时,协程会随着 viewModelScope 自动取消,避免内存泄漏。这点比老式回调强太多,不用手动标记状态判断是否该更新 UI。

小结一下关键点

用协程做网络请求,核心就是三点:挂起函数定义请求、viewModelScope 启动、try-catch 处理异常。代码扁平,逻辑直白,出问题也容易定位。现在主流网络库都原生支持协程,接入成本很低,新项目没理由不用。