引言
"用户点击按钮后应用卡死2秒,然后突然显示数据。"——这是我在Code Review时听到最多的问题描述之一。
几年前,我接手过一个Android项目,代码里充斥着各种Thread { ... }.start(),还有大量的runOnUiThread,以及让人头疼的内存泄漏。每次用户旋转屏幕,网络请求都会重新发起;当用户快速点击按钮时,多个请求并发执行导致界面显示错乱。最糟糕的是,当Activity销毁后,后台线程仍在运行,持有Activity引用,造成内存泄漏。
Kotlin协程彻底改变了这一切。 配合Android的生命周期感知组件(ViewModel、Lifecycle),协程让异步编程变得简单、安全、高效。Google官方已经将协程作为Android异步编程的首选方案,Jetpack库全面支持协程。
本文将系统讲解Kotlin协程在Android开发中的最佳实践,涵盖:
- 协程作用域的正确使用(lifecycleScope、viewModelScope、GlobalScope)
- 网络请求、数据库操作、文件读写的协程实践
- UI更新与线程切换
- 异常处理与错误传播
- 性能优化与常见陷阱
无论你是协程新手,还是想深入掌握协程在Android中的应用,这篇文章都会给你带来价值。
一、Android协程生态概览
1.1 协程在Android架构中的位置
在现代Android开发中,协程与以下组件深度集成:
架构组件层:
ViewModel- 提供viewModelScope,自动取消协程Lifecycle- 提供lifecycleScope,生命周期感知LiveData- 通过liveData {}构建器支持协程Room- 原生支持suspend函数
网络层:
- Retrofit - 通过
suspend关键字支持协程 - OkHttp - 非阻塞I/O,与协程完美配合
数据持久化层:
- Room Database -
@Dao接口支持suspend函数 - DataStore - 完全基于协程和Flow
1.2 核心依赖配置
在build.gradle.kts中添加必要的依赖:
dependencies {
// 协程核心库
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
// Lifecycle与协程集成
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
// Room与协程集成
implementation("androidx.room:room-ktx:2.6.1")
// Retrofit与协程集成
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2")
}
1.3 三大协程作用域
Android提供了三个主要的协程作用域:
| 作用域 | 生命周期 | 调度器 | 使用场景 |
|---|---|---|---|
viewModelScope | ViewModel生命周期 | Dispatchers.Main | ViewModel中的数据加载 |
lifecycleScope | Activity/Fragment生命周期 | Dispatchers.Main | UI相关操作 |
GlobalScope | 应用进程生命周期 | 需手动指定 | ❌ 通常不推荐使用 |
核心原则: 始终使用生命周期感知的作用域,避免内存泄漏和不必要的计算。
二、ViewModel中的协程实践
2.1 viewModelScope的正确使用
viewModelScope是ViewModel的扩展属性,当ViewModel被清除时自动取消所有协程。
基本用法:
class UserViewModel(
private val userRepository: UserRepository
) : ViewModel() {
private val _userState = MutableStateFlow<UiState<User>>(UiState.Loading)
val userState: StateFlow<UiState<User>> = _userState.asStateFlow()
fun loadUser(userId: String) {
viewModelScope.launch {
_userState.value = UiState.Loading
try {
val user = userRepository.getUser(userId)
_userState.value = UiState.Success(user)
} catch (e: Exception) {
_userState.value = UiState.Error(e.message ?: "Unknown error")
}
}
}
}
sealed class UiState<out T> {
object Loading : UiState<Nothing>()
data class Success<T>(val data: T) : UiState<T>()
data class Error(val message: String) : UiState<Nothing>()
}
关键点:
- 使用
viewModelScope.launch启动协程,无需手动取消 - 使用
StateFlow暴露UI状态,替代LiveData - 在协程中处理异常,转换为UI状态
2.2 并发请求优化
场景: 需要同时加载用户信息、好友列表和帖子列表。
❌ 错误方式:串行执行
// 串行执行:总耗时 = time1 + time2 + time3
suspend fun loadAllData(userId: String) {
val user = userRepository.getUser(userId) // 1秒
val friends = friendsRepository.getFriends(userId) // 1秒
val posts = postsRepository.getPosts(userId) // 1秒
// 总耗时:3秒
}
✅ 正确方式:并发执行
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
suspend fun loadAllData(userId: String): Triple<User, List<Friend>, List<Post>> {
return coroutineScope {
// 并发执行三个请求
val userDeferred = async { userRepository.getUser(userId) }
val friendsDeferred = async { friendsRepository.getFriends(userId) }
val postsDeferred = async { postsRepository.getPosts(userId) }
// 等待所有结果
Triple(
userDeferred.await(),
friendsDeferred.await(),
postsDeferred.await()
)
}
// 总耗时:约1秒(最慢的那个请求)
}
在ViewModel中使用:
class DashboardViewModel(
private val userRepository: UserRepository,
private val friendsRepository: FriendsRepository,
private val postsRepository: PostsRepository
) : ViewModel() {
private val _dashboardState = MutableStateFlow<DashboardState>(DashboardState.Loading)
val dashboardState = _dashboardState.asStateFlow()
fun loadDashboard(userId: String) {
viewModelScope.launch {
_dashboardState.value = DashboardState.Loading
try {
val (user, friends, posts) = loadAllData(userId)
_dashboardState.value = DashboardState.Success(
Dashboard(user, friends, posts)
)
} catch (e: Exception) {
_dashboardState.value = DashboardState.Error(e.message ?: "加载失败")
}
}
}
private suspend fun loadAllData(userId: String): Triple<User, List<Friend>, List<Post>> {
return coroutineScope {
val userDeferred = async { userRepository.getUser(userId) }
val friendsDeferred = async { friendsRepository.getFriends(userId) }
val postsDeferred = async { postsRepository.getPosts(userId) }
Triple(
userDeferred.await(),
friendsDeferred.await(),
postsDeferred.await()
)
}
}
}
性能对比:
- 串行执行:3秒
- 并发执行:1秒
- 性能提升:67%
2.3 处理用户操作防抖
场景: 用户在搜索框输入时实时搜索,避免频繁请求。
class SearchViewModel(
private val searchRepository: SearchRepository
) : ViewModel() {
private val _searchQuery = MutableStateFlow("")
private val _searchResults = MutableStateFlow<List<SearchResult>>(emptyList())
val searchResults = _searchResults.asStateFlow()
init {
// 使用Flow操作符实现防抖
viewModelScope.launch {
_searchQuery
.debounce(300) // 300ms防抖
.distinctUntilChanged() // 去重
.filter { it.length >= 2 } // 至少2个字符才搜索
.collectLatest { query ->
searchInternal(query)
}
}
}
fun updateQuery(query: String) {
_searchQuery.value = query
}
private suspend fun searchInternal(query: String) {
try {
val results = searchRepository.search(query)
_searchResults.value = results
} catch (e: Exception) {
_searchResults.value = emptyList()
}
}
}
UI层调用:
class SearchActivity : AppCompatActivity() {
private val viewModel: SearchViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding.searchEditText.addTextChangedListener { text ->
viewModel.updateQuery(text.toString())
}
lifecycleScope.launch {
viewModel.searchResults.collect { results ->
updateSearchResults(results)
}
}
}
}
关键点:
- 使用
debounce(300)实现300ms防抖 distinctUntilChanged()避免重复查询collectLatest确保只处理最新的搜索结果
三、网络请求的协程实践
3.1 Retrofit与协程集成
定义API接口:
interface ApiService {
@GET("users/{id}")
suspend fun getUser(@Path("id") userId: String): User
@POST("users")
suspend fun createUser(@Body user: User): User
@GET("users/{id}/posts")
suspend fun getUserPosts(
@Path("id") userId: String,
@Query("page") page: Int
): List<Post>
}
Repository层封装:
class UserRepository(
private val apiService: ApiService,
private val userDao: UserDao
) {
// 先从本地获取,再从网络更新
suspend fun getUser(userId: String): User {
return withContext(Dispatchers.IO) {
try {
// 尝试从网络获取最新数据
val user = apiService.getUser(userId)
// 缓存到本地数据库
userDao.insertUser(user)
user
} catch (e: Exception) {
// 网络失败,从本地数据库获取
userDao.getUserById(userId) ?: throw e
}
}
}
// 分页加载帖子
suspend fun getUserPosts(userId: String, page: Int): List<Post> {
return withContext(Dispatchers.IO) {
apiService.getUserPosts(userId, page)
}
}
}
3.2 处理网络错误与重试
实现智能重试机制:
// 重试扩展函数
suspend fun <T> retryIO(
times: Int = 3,
initialDelay: Long = 100,
maxDelay: Long = 1000,
factor: Double = 2.0,
block: suspend () -> T
): T {
var currentDelay = initialDelay
repeat(times - 1) { attempt ->
try {
return block()
} catch (e: IOException) {
// 网络错误,进行重试
delay(currentDelay)
currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay)
}
}
return block() // 最后一次尝试,失败则抛出异常
}
// 在Repository中使用
class UserRepository(private val apiService: ApiService) {
suspend fun getUserWithRetry(userId: String): User {
return withContext(Dispatchers.IO) {
retryIO(times = 3) {
apiService.getUser(userId)
}
}
}
}
处理不同类型的网络错误:
sealed class NetworkResult<out T> {
data class Success<T>(val data: T) : NetworkResult<T>()
data class Error(val exception: Exception) : NetworkResult<Nothing>()
object Loading : NetworkResult<Nothing>()
}
suspend fun <T> safeApiCall(
apiCall: suspend () -> T
): NetworkResult<T> {
return withContext(Dispatchers.IO) {
try {
NetworkResult.Success(apiCall())
} catch (e: HttpException) {
// HTTP错误(4xx, 5xx)
NetworkResult.Error(Exception("网络请求失败: ${e.code()}"))
} catch (e: IOException) {
// 网络连接错误
NetworkResult.Error(Exception("网络连接失败"))
} catch (e: Exception) {
// 其他未知错误
NetworkResult.Error(Exception("未知错误: ${e.message}"))
}
}
}
// 在ViewModel中使用
fun loadUser(userId: String) {
viewModelScope.launch {
_userState.value = UiState.Loading
when (val result = safeApiCall { userRepository.getUser(userId) }) {
is NetworkResult.Success -> {
_userState.value = UiState.Success(result.data)
}
is NetworkResult.Error -> {
_userState.value = UiState.Error(result.exception.message ?: "未知错误")
}
is NetworkResult.Loading -> {
// 不处理
}
}
}
}
3.3 请求取消与超时
设置超时:
suspend fun getUserWithTimeout(userId: String): User {
return withContext(Dispatchers.IO) {
withTimeout(5000) { // 5秒超时
apiService.getUser(userId)
}
}
}
// 或者使用withTimeoutOrNull返回null而不是抛出异常
suspend fun getUserWithTimeoutOrNull(userId: String): User? {
return withContext(Dispatchers.IO) {
withTimeoutOrNull(5000) {
apiService.getUser(userId)
}
}
}
取消正在进行的请求:
class UserViewModel(
private val userRepository: UserRepository
) : ViewModel() {
private var loadUserJob: Job? = null
fun loadUser(userId: String) {
// 取消之前的请求
loadUserJob?.cancel()
loadUserJob = viewModelScope.launch {
_userState.value = UiState.Loading
try {
val user = userRepository.getUser(userId)
_userState.value = UiState.Success(user)
} catch (e: CancellationException) {
// 协程被取消,不处理
} catch (e: Exception) {
_userState.value = UiState.Error(e.message ?: "未知错误")
}
}
}
fun cancelLoadUser() {
loadUserJob?.cancel()
}
}
四、数据库操作的协程实践
4.1 Room与协程集成
定义DAO接口:
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getUserById(userId: String): User?
@Query("SELECT * FROM users")
fun getAllUsersFlow(): Flow<List<User>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: User)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUsers(users: List<User>)
@Delete
suspend fun deleteUser(user: User)
@Query("DELETE FROM users WHERE id = :userId")
suspend fun deleteUserById(userId: String)
}
在Repository中使用:
class UserRepository(
private val userDao: UserDao,
private val apiService: ApiService
) {
// 从数据库读取用户(Flow自动在IO线程执行)
fun observeUsers(): Flow<List<User>> {
return userDao.getAllUsersFlow()
}
// 从网络获取并缓存
suspend fun refreshUsers() {
withContext(Dispatchers.IO) {
val users = apiService.getUsers()
userDao.insertUsers(users)
}
}
// 单一数据源模式(Single Source of Truth)
fun getUser(userId: String): Flow<User?> = flow {
// 1. 先发射数据库中的数据
emit(userDao.getUserById(userId))
// 2. 从网络获取最新数据
try {
val user = apiService.getUser(userId)
userDao.insertUser(user)
// 数据库更新后,Flow会自动发射新值
} catch (e: Exception) {
// 网络错误,使用数据库缓存
}
}.flowOn(Dispatchers.IO)
}
4.2 实现离线优先策略
完整的离线优先实现:
class PostRepository(
private val postDao: PostDao,
private val apiService: ApiService,
private val connectivityManager: ConnectivityManager
) {
// 观察帖子列表(离线优先)
fun observePosts(): Flow<List<Post>> = flow {
// 1. 立即发射本地缓存
emitAll(postDao.getAllPostsFlow())
// 2. 如果有网络,从服务器同步
if (isNetworkAvailable()) {
try {
val posts = apiService.getPosts()
postDao.insertPosts(posts)
// 数据库更新后会自动触发新的emit
} catch (e: Exception) {
// 网络同步失败,继续使用本地缓存
}
}
}.flowOn(Dispatchers.IO)
// 刷新(强制从网络加载)
suspend fun refresh(): Result<Unit> {
return withContext(Dispatchers.IO) {
try {
val posts = apiService.getPosts()
postDao.deleteAllPosts()
postDao.insertPosts(posts)
Result.success(Unit)
} catch (e: Exception) {
Result.failure(e)
}
}
}
private fun isNetworkAvailable(): Boolean {
val network = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
}
}
在ViewModel中使用:
class PostListViewModel(
private val postRepository: PostRepository
) : ViewModel() {
val posts: StateFlow<List<Post>> = postRepository.observePosts()
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = emptyList()
)
private val _isRefreshing = MutableStateFlow(false)
val isRefreshing = _isRefreshing.asStateFlow()
fun refresh() {
viewModelScope.launch {
_isRefreshing.value = true
postRepository.refresh()
_isRefreshing.value = false
}
}
}
4.3 批量操作优化
场景: 插入大量数据时使用事务提升性能。
@Dao
interface PostDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertPosts(posts: List<Post>)
// 使用事务批量删除并插入
@Transaction
suspend fun replaceAllPosts(posts: List<Post>) {
deleteAllPosts()
insertPosts(posts)
}
@Query("DELETE FROM posts")
suspend fun deleteAllPosts()
}
// 在Repository中使用
suspend fun syncPosts() {
withContext(Dispatchers.IO) {
val posts = apiService.getPosts()
postDao.replaceAllPosts(posts) // 事务中执行,保证原子性
}
}
五、UI更新与线程切换
5.1 Dispatchers详解
Kotlin协程提供了四种调度器:
| Dispatcher | 用途 | 线程池 |
|---|---|---|
Dispatchers.Main | UI更新、轻量级操作 | 主线程 |
Dispatchers.IO | 网络、文件、数据库 | 共享线程池(最多64线程) |
Dispatchers.Default | CPU密集型计算 | 线程数=CPU核心数 |
Dispatchers.Unconfined | 不限制线程(不推荐) | 调用者线程 |
最佳实践:
viewModelScope.launch {
// 在主线程启动协程
val user = withContext(Dispatchers.IO) {
// 切换到IO线程执行网络请求
apiService.getUser(userId)
}
// 自动切回主线程
// 更新UI(在主线程)
binding.userName.text = user.name
}
5.2 避免不必要的线程切换
❌ 过度切换:
suspend fun loadData() {
withContext(Dispatchers.IO) {
val data = apiService.getData()
withContext(Dispatchers.Main) {
// 不必要的切换
updateUI(data)
}
}
}
✅ 优化后:
suspend fun loadData() {
val data = withContext(Dispatchers.IO) {
apiService.getData()
}
// 自动在主线程
updateUI(data)
}
5.3 在Activity/Fragment中收集Flow
使用lifecycleScope与repeatOnLifecycle:
class UserProfileFragment : Fragment() {
private val viewModel: UserViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// ✅ 推荐:生命周期感知
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
// 只在STARTED状态收集Flow
viewModel.userState.collect { state ->
when (state) {
is UiState.Loading -> showLoading()
is UiState.Success -> showUser(state.data)
is UiState.Error -> showError(state.message)
}
}
}
}
}
}
为什么使用repeatOnLifecycle(STARTED):
- Fragment在后台时停止收集,节省资源
- Fragment回到前台时自动恢复收集
- 避免内存泄漏和不必要的UI更新
六、异常处理与错误传播
6.1 协程中的异常类型
两种异常类型:
- CancellationException: 协程取消,不会传播
- 其他异常: 会传播到父协程,导致整个协程树取消
示例:
viewModelScope.launch {
launch {
delay(100)
throw RuntimeException("子协程异常")
// 这个异常会传播到父协程,导致viewModelScope取消
}
launch {
delay(200)
println("这行代码不会执行") // 父协程已被取消
}
}
6.2 使用SupervisorJob隔离异常
SupervisorJob: 子协程异常不会影响其他子协程。
val supervisorScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
supervisorScope.launch {
launch {
delay(100)
throw RuntimeException("子协程1异常")
// 这个异常不会影响子协程2
}
launch {
delay(200)
println("子协程2继续执行") // 会执行
}
}
在ViewModel中使用SupervisorJob:
class RobustViewModel : ViewModel() {
private val supervisorJob = SupervisorJob()
private val scope = CoroutineScope(supervisorJob + Dispatchers.Main)
fun loadMultipleData() {
scope.launch {
// 启动多个独立的子任务
launch {
try {
loadUserData()
} catch (e: Exception) {
handleError("用户数据加载失败", e)
}
}
launch {
try {
loadPostsData()
} catch (e: Exception) {
handleError("帖子数据加载失败", e)
}
}
}
}
override fun onCleared() {
super.onCleared()
supervisorJob.cancel()
}
}
6.3 全局异常处理
设置CoroutineExceptionHandler:
val exceptionHandler = CoroutineExceptionHandler { _, exception ->
Log.e("Coroutine", "捕获到未处理的异常", exception)
// 上报到崩溃收集平台(如Firebase Crashlytics)
}
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main + exceptionHandler)
scope.launch {
throw RuntimeException("未捕获的异常")
// 会被exceptionHandler捕获
}
在Application中设置全局处理器:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// 设置全局协程异常处理器
Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
Log.e("GlobalHandler", "未捕获的异常", throwable)
// 上报崩溃
FirebaseCrashlytics.getInstance().recordException(throwable)
}
}
}
七、性能优化与常见陷阱
7.1 避免内存泄漏
❌ 陷阱1: 使用GlobalScope
class LeakyActivity : AppCompatActivity() {
fun loadData() {
GlobalScope.launch {
// 危险!Activity销毁后协程仍在运行
val data = fetchData()
updateUI(data) // 可能访问已销毁的Activity
}
}
}
✅ 正确方式: 使用lifecycleScope
class SafeActivity : AppCompatActivity() {
fun loadData() {
lifecycleScope.launch {
// Activity销毁时自动取消
val data = fetchData()
updateUI(data)
}
}
}
❌ 陷阱2: 静态引用持有Context
companion object {
var coroutineJob: Job? = null // 危险!
}
fun loadData(context: Context) {
coroutineJob = GlobalScope.launch {
// context可能是Activity,导致内存泄漏
val data = fetchData(context)
}
}
✅ 正确方式: 使用Application Context
fun loadData(context: Context) {
val appContext = context.applicationContext
viewModelScope.launch {
val data = fetchData(appContext)
}
}
7.2 控制并发数量
问题: 同时发起1000个网络请求导致OOM。
✅ 解决方案: 使用Semaphore限流
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
class ImageLoader {
private val semaphore = Semaphore(5) // 最多5个并发
suspend fun loadImages(urls: List<String>): List<Bitmap> {
return urls.map { url ->
async {
semaphore.withPermit {
// 最多同时执行5个
loadImage(url)
}
}
}.awaitAll()
}
private suspend fun loadImage(url: String): Bitmap {
// 下载图片
return withContext(Dispatchers.IO) {
// 实际下载逻辑
TODO()
}
}
}
7.3 使用Channel避免背压问题
场景: 生产者速度 >> 消费者速度,导致内存占用暴涨。
❌ 使用Flow(无背压控制)
fun produceData(): Flow<Data> = flow {
repeat(1_000_000) {
emit(Data(it)) // 快速发射数据
}
}
fun consumeData() {
viewModelScope.launch {
produceData().collect { data ->
delay(10) // 消费慢
process(data)
}
}
}
✅ 使用Channel(有容量限制)
val channel = Channel<Data>(capacity = 100) // 缓冲100个元素
fun produceData() {
viewModelScope.launch {
repeat(1_000_000) {
channel.send(Data(it)) // 缓冲满时挂起
}
channel.close()
}
}
fun consumeData() {
viewModelScope.launch {
for (data in channel) {
delay(10)
process(data)
}
}
}
7.4 避免阻塞Dispatchers.IO线程池
❌ 在IO线程池执行CPU密集型任务
suspend fun processLargeData(data: List<Int>) {
withContext(Dispatchers.IO) {
// CPU密集型计算,占用IO线程
data.map { it * it * it }.sorted()
}
}
✅ 使用Dispatchers.Default
suspend fun processLargeData(data: List<Int>) {
withContext(Dispatchers.Default) {
// CPU密集型任务使用Default
data.map { it * it * it }.sorted()
}
}
八、总结与最佳实践清单
核心要点回顾
-
使用生命周期感知的作用域
viewModelScopefor ViewModellifecycleScopefor Activity/Fragment- 避免使用
GlobalScope
-
线程切换
Dispatchers.Main- UI操作Dispatchers.IO- 网络、文件、数据库Dispatchers.Default- CPU密集型计算
-
错误处理
- 使用
try-catch处理已知异常 - 使用
SupervisorJob隔离子协程异常 - 设置
CoroutineExceptionHandler全局捕获
- 使用
-
性能优化
- 使用
async并发执行独立任务 - 使用
Semaphore控制并发数量 - 避免在循环中创建协程
- 使用
-
数据流管理
- 使用
StateFlow替代LiveData - 使用
repeatOnLifecycle收集Flow - 实现离线优先策略
- 使用
最佳实践检查清单
作用域管理:
- 使用
viewModelScope在ViewModel中启动协程 - 使用
lifecycleScope在Activity/Fragment中启动协程 - 避免使用
GlobalScope - 在自定义作用域时使用
SupervisorJob
线程调度:
- 网络请求使用
Dispatchers.IO - 数据库操作使用
Dispatchers.IO - CPU密集型计算使用
Dispatchers.Default - UI更新在
Dispatchers.Main
异常处理:
- 在协程顶层使用
try-catch - 区分
CancellationException和其他异常 - 使用
CoroutineExceptionHandler记录未捕获异常 - 在Repository层捕获并转换异常
性能优化:
- 使用
async并发执行独立任务 - 使用
Semaphore限制并发数量 - 避免阻塞Dispatcher线程池
- 使用
Flow.buffer()控制背压
测试:
- 使用
runTest测试suspend函数 - 使用
StandardTestDispatcher控制测试时间 - Mock Repository和API
- 测试不同的UI状态
学习资源
官方文档:
- Kotlin协程官方指南: kotlinlang.org/docs/corout…
- Android协程最佳实践: developer.android.com/kotlin/coro…
推荐阅读:
- 《Kotlin Coroutines by Tutorials》
- 《Asynchronous Programming with Kotlin》
- Roman Elizarov的博客(协程库作者)
视频教程:
- Android Developers YouTube频道 - Coroutines系列
- Kotlin Conf演讲 - Coroutines相关主题
系列文章导航:
- 👉 上一篇: 性能优化:内联、内存与字节码分析
- 👉 下一篇: 进阶之路:从语言特性到架构思维
如果这篇文章对你有帮助,欢迎点赞、收藏、分享!有任何问题或建议,欢迎在评论区留言讨论。让我们一起学习,一起成长!
也欢迎访问我的个人主页发现更多宝藏资源