题目
Android中如何安全使用协程处理网络请求并防止内存泄漏
信息
- 类型:问答
- 难度:⭐⭐
考点
Kotlin协程, Android生命周期感知, 内存泄漏防范
快速回答
在Android中使用协程处理网络请求时,需注意:
- 使用
viewModelScope或lifecycleScope自动管理生命周期 - 避免在
Activity/Fragment中直接启动协程 - 使用
coroutineScope或supervisorScope处理异常 - 通过
viewModelScope.launch启动协程,ViewModel销毁时自动取消
核心问题
在Android中直接启动协程处理网络请求可能导致:
- 组件销毁后协程继续运行引发内存泄漏
- 组件重建时产生僵尸协程
- 异常未捕获导致应用崩溃
解决方案与代码示例
1. 使用ViewModel作用域
class MyViewModel : ViewModel() {
fun fetchData() {
viewModelScope.launch {
try {
val data = withContext(Dispatchers.IO) {
repository.getData() // 模拟网络请求
}
_dataLiveData.value = data
} catch (e: Exception) {
// 处理异常
}
}
}
}2. Fragment中使用lifecycleScope
class MyFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycleScope.launchWhenStarted {
try {
val result = withContext(Dispatchers.IO) {
apiService.fetchData()
}
updateUI(result)
} catch (e: Exception) {
showError(e)
}
}
}
}最佳实践
- 作用域选择:
- 业务逻辑使用
viewModelScope - UI相关操作使用
lifecycleScope
- 业务逻辑使用
- 线程调度:
- 网络请求使用
Dispatchers.IO - UI更新使用
Dispatchers.Main
- 网络请求使用
- 异常处理:
- 使用
try/catch捕获具体异常 - 使用
CoroutineExceptionHandler全局处理
- 使用
常见错误
- 错误1:在Activity中直接启动协程
// 危险!可能内存泄漏 class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { GlobalScope.launch { // 错误示范 val data = fetchData() runOnUiThread { updateUI(data) } } } } - 错误2:忽略协程取消
viewModelScope.launch { val job = async(Dispatchers.IO) { heavyTask() } // 忘记检查isActive状态 job.await() // 即使ViewModel销毁仍会等待 }
原理说明
- 生命周期绑定:
viewModelScope在ViewModel.onCleared()时自动取消所有子协程 - 结构化并发:协程作用域形成父子关系,父作用域取消时自动传播到子协程
- 内存安全:通过生命周期感知组件避免持有已销毁Activity的引用
扩展知识
- 状态恢复:使用
SavedStateHandle保存协程结果 - 复杂流程:
- 使用
flow处理数据流 - 结合
LiveData使用liveData { }构建器
- 使用
- 性能优化:
- 使用
async并行请求 - 通过
coroutineScope创建子作用域
- 使用
// 并行请求示例
viewModelScope.launch {
coroutineScope {
val userDeferred = async { getUserData() }
val newsDeferred = async { getNewsFeed() }
val user = userDeferred.await()
val news = newsDeferred.await()
mergeData(user, news)
}
}