在 Android 开发中,多线程编程是处理耗时操作(如网络请求、数据库读写、复杂计算)的核心技术,目的是避免阻塞主线程(UI 线程),确保应用流畅响应。以下是 Android 多线程编程的详细解析,涵盖关键机制、最佳实践和 Kotlin 示例代码。
1. Android 线程模型
- 主线程(UI 线程):负责处理 UI 更新和用户交互。禁止在主线程执行耗时操作,否则会导致应用无响应(ANR)。
- 工作线程(后台线程):用于执行耗时任务,需通过线程间通信将结果返回主线程更新 UI。
2. 多线程实现方式
(1) Thread + Handler(传统方式)
kotlin
// 创建工作线程执行任务
val backgroundThread = Thread {
// 模拟耗时操作
Thread.sleep(2000)
val result = "任务完成"
// 通过 Handler 发送结果到主线程
Handler(Looper.getMainLooper()).post {
textView.text = result
}
}
backgroundThread.start()
缺点:手动管理线程生命周期复杂,易引发内存泄漏。
(2) AsyncTask(已弃用)
kotlin
@Deprecated("Use coroutines or other modern APIs instead.")
class MyAsyncTask : AsyncTask<Void, Void, String>() {
override fun doInBackground(vararg params: Void?): String {
// 后台执行
return "结果"
}
override fun onPostExecute(result: String) {
// 主线程更新 UI
textView.text = result
}
}
// 启动任务
MyAsyncTask().execute()
缺点:已弃用,无法处理配置变更(如屏幕旋转),容易内存泄漏。
(3) HandlerThread
结合 Handler
和 Looper
的专用线程,适合长时间运行的任务。
kotlin
val handlerThread = HandlerThread("MyHandlerThread").apply { start() }
val handler = Handler(handlerThread.looper)
handler.post {
// 后台执行任务
val result = doWork()
// 发送结果到主线程
runOnUiThread { textView.text = result }
}
(4) ThreadPoolExecutor
管理线程池,复用线程资源,适合高频短任务。
kotlin
val executor = Executors.newFixedThreadPool(4)
executor.execute {
val result = doWork()
runOnUiThread { textView.text = result }
}
// 关闭线程池(在 onDestroy 中调用)
executor.shutdown()
(5) Kotlin 协程(推荐)
协程是轻量级线程,通过挂起(suspend)机制简化异步代码,避免回调地狱。
添加依赖
gradle
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
示例代码
kotlin
// 在 ViewModel 或 LifecycleScope 中启动协程
class MyViewModel : ViewModel() {
fun fetchData() {
viewModelScope.launch {
// 在主线程启动协程
val result = withContext(Dispatchers.IO) {
// 切换到 IO 线程执行耗时操作
doWork()
}
// 自动切回主线程更新 UI
textView.text = result
}
}
private suspend fun doWork(): String {
delay(2000) // 模拟耗时操作
return "数据加载完成"
}
}
优势:
- 结构化并发:自动取消关联任务。
- 生命周期感知:与
ViewModel
或Lifecycle
绑定,避免内存泄漏。 - 简洁语法:用同步代码风格写异步逻辑。
(6) WorkManager(后台任务调度)
处理延迟、周期性或约束条件(如网络连接)的后台任务。
kotlin
// 定义 Worker
class MyWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
// 执行后台任务
return Result.success()
}
}
// 调度任务
val request = OneTimeWorkRequestBuilder<MyWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
WorkManager.getInstance(context).enqueue(request)
3. 线程间通信
(1) Handler(传统方式)
kotlin
val mainHandler = Handler(Looper.getMainLooper())
mainHandler.post {
textView.text = "更新 UI"
}
(2) LiveData
结合 ViewModel
实现数据驱动 UI。
kotlin
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> get() = _data
fun loadData() {
viewModelScope.launch(Dispatchers.IO) {
val result = fetchFromNetwork()
_data.postValue(result) // 切换到主线程更新 LiveData
}
}
}
// 在 Activity/Fragment 中观察
viewModel.data.observe(this) { result ->
textView.text = result
}
(3) Flow
协程中的数据流,适合连续数据更新。
kotlin
fun fetchData(): Flow<String> = flow {
repeat(5) {
emit("数据块 $it")
delay(1000)
}
}
// 收集数据
lifecycleScope.launch {
fetchData()
.flowOn(Dispatchers.IO) // 指定数据生产线程
.collect { value ->
textView.text = value // 在主线程消费数据
}
}
4. 避免内存泄漏
- 取消协程:通过
viewModelScope
或lifecycleScope
自动管理。 - 弱引用:避免在后台线程持有 Activity/Fragment 的强引用。
kotlin
class MyActivity : AppCompatActivity() {
private val weakActivity = WeakReference(this)
fun startTask() {
CoroutineScope(Dispatchers.IO).launch {
val activity = weakActivity.get() ?: return@launch
// 使用 activity 更新 UI
}
}
}
5. 最佳实践
- 主线程仅处理 UI 更新:所有耗时操作移至工作线程。
- 优先使用协程:替代
AsyncTask
和RxJava
,简化异步代码。 - 合理选择线程池:I/O 密集型用
Dispatchers.IO
,计算密集型用Dispatchers.Default
。 - 处理异常:使用
try/catch
或CoroutineExceptionHandler
捕获后台任务错误。
kotlin
val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
Log.e("Coroutine", "Error: ${throwable.message}")
}
viewModelScope.launch(exceptionHandler) {
// 可能抛出异常的操作
}
总结
机制 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
Thread+Handler | 简单后台任务 | 灵活 | 手动管理复杂,易泄漏 |
协程 | 所有异步场景(推荐) | 简洁、结构化并发、生命周期感知 | 需学习新概念 |
WorkManager | 延迟/周期性后台任务 | 系统调度、支持约束条件 | 不适合即时任务 |
LiveData/Flow | 数据驱动 UI 更新 | 生命周期感知、响应式 | 需结合 ViewModel 使用 |
掌握多线程编程是 Android 高级开发的核心技能,合理选择工具能显著提升应用性能和用户体验。