协程:lifecycleScope与viewModelScope的区别是什么?
lifecycleScope 与 viewModelScope 的选择时机
适用场景区分
- lifecycleScope:和 Activity/Fragment 的生命周期严格绑定,组件销毁时协程会自动取消。适合做与当前UI组件生命周期强绑定的操作,比如:
- 监听UI控件的实时状态(如RecyclerView滚动监听)
- 执行仅在组件可见时才需要的临时UI更新
- 组件销毁后无需保留的短周期任务
- viewModelScope:绑定 ViewModel 的生命周期,配置变化(如屏幕旋转)时不会随组件销毁而取消,直到 ViewModel 真正被销毁(比如页面退出)。适合做需要跨配置变化保留的操作,比如:
- 发起网络请求获取数据,旋转屏幕后无需重新请求
- 处理本地数据库查询、数据缓存逻辑
- 维护页面的核心数据状态,确保配置变化后数据不丢失
Retrofit + 协程请求的注意事项与最佳实践
- 用 suspend 定义接口:Retrofit 支持直接将接口方法定义为 suspend 函数,无需手动创建 Call 对象,简化代码:
interface ApiService { @GET("users") suspend fun getUsers(): List<User> } - 强制处理异常:网络请求可能抛出 IOException、HttpException 等异常,必须用 try-catch 包裹请求逻辑,或者通过
CoroutineExceptionHandler统一处理,避免崩溃:viewModelScope.launch { try { val users = apiService.getUsers() // 处理成功状态 } catch (e: IOException) { // 处理网络异常(无网、连接超时等) } catch (e: HttpException) { // 处理HTTP错误状态码(4xx、5xx) } } - 依赖作用域自动取消请求:永远不要用
GlobalScope发起网络请求,而是使用viewModelScope或lifecycleScope。当作用域生命周期结束时,协程会自动取消请求,避免内存泄露和无效请求继续执行。 - 无需手动切换线程:Retrofit 的 suspend 函数内部已经默认在 IO 线程执行网络操作,而
viewModelScope/lifecycleScope默认运行在 Main 线程,所以调用 suspend 接口时会自动切换到 IO 线程,请求完成后切回 Main 线程更新UI,无需手动指定withContext(Dispatchers.IO)。 - 统一管理请求状态:建议用密封类封装请求的不同状态(加载中、成功、失败),让UI层能清晰响应不同状态:
sealed class RequestState<out T> { object Loading : RequestState<Nothing>() data class Success<out T>(val data: T) : RequestState<T>() data class Error(val message: String) : RequestState<Nothing>() } - 避免重复请求:在发起请求前,可先判断当前是否处于加载状态,或者用 Flow 的
distinctUntilChanged等操作符,防止用户重复触发相同请求。 - 合理使用缓存:结合 Retrofit 的缓存配置(如添加 Cache 拦截器),在无网时返回缓存数据,提升用户体验。
内容的提问来源于stack exchange,提问作者Regress.arg
相关产品推荐
相关产品推荐

