做Android开发的朋友应该都遇到过这样的场景:点一下“刷新”按钮,界面卡了几秒才出数据,用户皱眉。其实问题就出在主线程被网络请求堵住了。Kotlin协程就是来解决这类问题的,它让异步操作写起来像同步代码一样清爽。今天不讲理论,直接上一个真实项目中的小例子。
一个天气App的请求优化
假设我们有个简单的天气应用,点击“获取天气”时要从网络拉数据,然后更新UI。不用协程的时候,你得开子线程、回调嵌套,稍不注意就出错。用Kotlin协程后,代码变得特别直观。
class WeatherActivity : AppCompatActivity() {
private val scope = CoroutineScope(Dispatchers.Main)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_weather)
btn_fetch.setOnClickListener {
fetchWeather()
}
}
private fun fetchWeather() {
scope.launch {
try {
progressBar.visibility = View.VISIBLE
val result = withContext(Dispatchers.IO) {
// 模拟网络请求
delay(2000)
"晴,26℃"
}
tv_result.text = result
} catch (e: Exception) {
tv_result.text = "加载失败"
} finally {
progressBar.visibility = View.GONE
}
}
}
override fun onDestroy() {
super.onDestroy()
scope.cancel()
}
}
这段代码里,launch启动一个协程,withContext(Dispatchers.IO)把耗时操作切到IO线程,主线程始终响应用户操作。等数据回来,自动切回主线程更新UI。整个过程清晰,没有回调地狱。
实际项目中的好处
我们在公司最近重构的一个电商App里全面用了协程。以前订单列表页经常因为图片加载和接口并发导致卡顿,现在每个请求独立协程处理,还能用async/await做并行聚合。比如同时拉订单信息和用户优惠券,谁慢等谁,整体快了一截。
更实用的是错误处理。以前多个异步任务,一个出错很难定位。现在用try-catch包住整个流程,日志打出来一目了然,运维也省心。
别忘了取消和资源管理
协程不是开了就完事了。上面例子中用了CoroutineScope绑定生命周期,onDestroy时主动cancel,避免内存泄漏。这在实际项目里特别重要——用户点进详情页,数据还没回来就退出了,协程得及时停下,不然浪费流量还可能报空指针。
如果你还在用Retrofit + Callback的方式,可以试试加上suspend函数。新版Retrofit原生支持协程,接口写起来超干净:
interface ApiService {
@GET("/weather")
suspend fun getWeather(): Response<WeatherData>
}
配合ViewModel和LiveData,一套完整的响应式链条就起来了。写多了你会发现,原本需要三四层嵌套的逻辑,现在七八行搞定。
协程不是银弹,但用对了真能少加不少班。特别是新项目,早点上手,后期维护轻松不少。