安卓应用的主线程(UI线程)负责界面渲染和用户交互,若执行耗时操作(如网络请求、数据库读写、复杂计算)会导致界面卡顿甚至触发”Application Not Responding(ANR)”,因此需要将耗时任务移至子线程执行,并通过线程间通信更新UI。
工具 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
Thread + Handler |
简单任务+UI更新 | 原生API,易于理解 | 需手动管理线程生命周期,代码冗余 |
AsyncTask |
单次异步任务+结果回调 | 简化代码结构,自动匹配UI线程 | 生命周期依赖Activity/Fragment,易内存泄漏 |
ExecutorService |
多任务并行/线程池管理 | 灵活控制线程数量,复用线程 | 需手动处理UI更新,API较底层 |
RxJava |
复杂异步链式调用 | 响应式编程,简化回调嵌套 | 学习成本高,背压处理需谨慎 |
Kotlin Coroutine |
现代异步编程(Android推荐) | 语法简洁,协程上下文自动切换 | 需理解悬挂函数原理,部分旧库不兼容 |
Handler机制
Handler.post(Runnable)
将任务投递到指定线程(如主线程) val handler = Handler(Looper.getMainLooper()) handler.post { textView.text = "更新UI" }
LiveData/Flow
// LiveData示例 val liveData = MutableLiveData<String>() liveData.observe(this) { textView.text = it } // 子线程更新 liveData.postValue("新数据")
Channel(Kotlin Coroutine)
val channel = Channel<Int>() launch { channel.send(1) } lifecycleScope.launch { val data = channel.receive() textView.text = data.toString() }
场景 | 推荐方案 | 原因 |
---|---|---|
单次网络请求+UI更新 | Kotlin Coroutine |
代码简洁,自动切换线程 |
多图片并行加载 | ExecutorService + ThreadPool |
精确控制并发数,复用线程 |
实时数据流处理 | RxJava |
支持事件组合/转换/背压处理 |
周期性后台任务 | WorkManager |
兼容系统调度,处理进程被杀恢复 |
问题1:为什么AsyncTask
在配置变更时容易崩溃?
AsyncTask
绑定到创建它的Activity
,配置变更后原实例被销毁,导致任务无法回调。 ViewModelScope
或Lifecycle.repeatOnLifecycle
绑定协程。问题2:协程如何取消未完成的任务?
Job
对象调用cancel()
,例如在ViewModel
清理时: viewModelScope.cancel() // 取消所有协程
A1:使用viewLifecycleOwner
绑定协程生命周期:
viewLifecycleOwner.lifecycleScope.launch { // 执行异步任务,自动在Fragment销毁时取消 }
RxJava
与Kotlin Coroutine
如何选择?A2:优先选协程,除非需要Rx特有功能:
debounce
)、组合复杂数据流、已有Rx生态依赖