01-01-02 协程作用域与生命周期完全指南
·
01-01-02 协程作用域与生命周期完全指南
目录
- 1. 协程作用域概念
- 2. GlobalScope
- 3. lifecycleScope
- 4. viewModelScope
- 5. 自定义作用域
- 6. 生命周期管理
- 7. 作用域传播
- 8. deviceSecurity实战案例
- 9. 最佳实践
- 10. 常见问题FAQ
1. 协程作用域概念
1.1 什么是协程作用域
协程作用域(CoroutineScope)定义了协程的生命周期边界,管理协程的创建、取消和完成。
/**
* 协程作用域基础
*/
class ScopeBasics {
// 作用域的本质
interface CoroutineScope {
val coroutineContext: CoroutineContext
}
// 创建基础作用域
fun createBasicScope() {
val scope = CoroutineScope(Dispatchers.Main)
scope.launch {
println("Running in scope")
}
// 取消作用域
scope.cancel()
}
// 作用域控制生命周期
fun scopeLifecycle() = runBlocking {
val scope = CoroutineScope(Job())
scope.launch {
repeat(5) {
delay(500)
println("Task $it")
}
}
delay(1200)
scope.cancel() // 取消所有协程
println("Scope cancelled")
}
}
1.2 作用域的作用
/**
* 协程作用域的三大作用
*/
class ScopePurpose {
// 1. 生命周期管理
fun lifecycleManagement() {
val scope = CoroutineScope(Job() + Dispatchers.Main)
// 启动多个协程
scope.launch { doWork1() }
scope.launch { doWork2() }
scope.launch { doWork3() }
// 一次性全部取消
scope.cancel()
}
// 2. 结构化并发
suspend fun structuredConcurrency() = coroutineScope {
launch { doWork1() }
launch { doWork2() }
// 等待所有子协程完成
}
// 3. 异常传播
suspend fun exceptionPropagation() {
try {
coroutineScope {
launch {
throw RuntimeException("Error")
}
launch {
delay(1000)
println("Won't execute")
}
}
} catch (e: Exception) {
println("Caught: ${e.message}")
}
}
private suspend fun doWork1() { delay(100) }
private suspend fun doWork2() { delay(100) }
private suspend fun doWork3() { delay(100) }
}
1.3 作用域的层次结构
/**
* 协程作用域的层次关系
*/
class ScopeHierarchy {
fun demonstrateHierarchy() = runBlocking {
println("Root")
launch {
println(" Parent")
launch {
println(" Child 1")
launch {
println(" GrandChild")
}
}
launch {
println(" Child 2")
}
}
}
// 父协程等待所有子协程
suspend fun parentWaitsChildren() = coroutineScope {
launch {
delay(1000)
println("Child 1 done")
}
launch {
delay(2000)
println("Child 2 done")
}
println("Parent waiting...")
// coroutineScope会等待所有子协程完成
}
// 父协程取消会取消所有子协程
suspend fun parentCancelsChildren() = coroutineScope {
val parent = launch {
launch {
try {
delay(Long.MAX_VALUE)
} catch (e: CancellationException) {
println("Child 1 cancelled")
}
}
launch {
try {
delay(Long.MAX_VALUE)
} catch (e: CancellationException) {
println("Child 2 cancelled")
}
}
delay(1000)
}
delay(500)
parent.cancel()
println("Parent cancelled")
}
}
2. GlobalScope
2.1 GlobalScope特点
/**
* GlobalScope: 全局作用域
*
* 特点:
* - 生命周期是整个应用进程
* - 不会自动取消
* - 不推荐使用
*/
class GlobalScopeExample {
// 基础用法
fun basicUsage() {
GlobalScope.launch {
delay(1000)
println("Global coroutine")
}
// 应用关闭前协程一直运行
}
// 问题示例: 内存泄漏
class LeakyActivity : AppCompatActivity() {
private lateinit var textView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ❌ 不推荐
GlobalScope.launch {
delay(10000)
textView.text = "Updated" // Activity已销毁,崩溃!
}
}
}
// 合理使用场景: 应用级别的后台任务
object AppLogger {
private val logQueue = Channel<String>(Channel.UNLIMITED)
init {
GlobalScope.launch {
for (log in logQueue) {
writeLogToFile(log)
}
}
}
fun log(message: String) {
logQueue.trySend(message)
}
private suspend fun writeLogToFile(log: String) {
withContext(Dispatchers.IO) {
File("app.log").appendText("$log\n")
}
}
}
}
2.2 为什么不推荐GlobalScope
/**
* GlobalScope的问题
*/
class GlobalScopeProblems {
// 问题1: 无法控制生命周期
class ProblemActivity : AppCompatActivity() {
fun loadData() {
GlobalScope.launch {
val data = fetchData() // 耗时操作
updateUI(data) // Activity可能已销毁
}
}
private suspend fun fetchData(): String {
delay(5000)
return "Data"
}
private fun updateUI(data: String) {
// 可能崩溃或泄漏
}
}
// 问题2: 难以测试
class DataManager {
fun loadData() {
GlobalScope.launch {
// 测试时无法等待完成
processData()
}
}
private suspend fun processData() {
delay(1000)
}
}
// 问题3: 资源泄漏
class ResourceLeaker {
private val resources = mutableListOf<Resource>()
fun doWork() {
GlobalScope.launch {
val resource = acquireResource()
resources.add(resource)
// 如果没有清理,资源会一直占用
delay(Long.MAX_VALUE)
}
}
private fun acquireResource(): Resource = Resource()
}
class Resource
}
2.3 替代方案
/**
* GlobalScope的替代方案
*/
class GlobalScopeAlternatives {
// 方案1: 使用lifecycleScope
class MyActivity : AppCompatActivity() {
fun loadData() {
lifecycleScope.launch {
val data = fetchData()
updateUI(data) // 安全,Activity销毁时自动取消
}
}
private suspend fun fetchData(): String {
delay(5000)
return "Data"
}
private fun updateUI(data: String) {}
}
// 方案2: 使用viewModelScope
class MyViewModel : ViewModel() {
fun loadData() {
viewModelScope.launch {
// ViewModel清除时自动取消
processData()
}
}
private suspend fun processData() {
delay(1000)
}
}
// 方案3: 自定义应用级作用域
object AppScope : CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext = Dispatchers.Main + job
fun cancelAll() {
job.cancel()
}
}
class AppLevelWork {
fun doWork() {
AppScope.launch {
// 应用级任务
processBackgroundData()
}
}
private suspend fun processBackgroundData() {
delay(1000)
}
}
}
3. lifecycleScope
3.1 lifecycleScope基础
/**
* lifecycleScope: Activity/Fragment的生命周期作用域
*
* 自动绑定生命周期:
* - Activity/Fragment销毁时自动取消
* - 安全的UI更新
*/
class LifecycleScopeBasics : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 基础用法
lifecycleScope.launch {
val data = fetchData()
updateUI(data) // 安全,Activity销毁时协程被取消
}
// 并发任务
lifecycleScope.launch {
coroutineScope {
val data1 = async { fetchData1() }
val data2 = async { fetchData2() }
val data3 = async { fetchData3() }
displayResults(data1.await(), data2.await(), data3.await())
}
}
}
private suspend fun fetchData(): String {
delay(1000)
return "Data"
}
private suspend fun fetchData1(): String {
delay(500)
return "Data1"
}
private suspend fun fetchData2(): String {
delay(500)
return "Data2"
}
private suspend fun fetchData3(): String {
delay(500)
return "Data3"
}
private fun updateUI(data: String) {}
private fun displayResults(d1: String, d2: String, d3: String) {}
}
3.2 生命周期感知
/**
* lifecycleScope的生命周期感知特性
*/
class LifecycleAwareness : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// repeatOnLifecycle: 在指定生命周期状态重复执行
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
// STARTED状态时执行
// STOPPED状态时取消
// STARTED状态时再次执行
collectDataFlow()
}
}
// launchWhenStarted: STARTED状态及以上时执行
lifecycleScope.launchWhenStarted {
// STARTED状态时开始
// STOPPED状态时挂起(不是取消)
// STARTED状态时继续
updateUI()
}
// launchWhenResumed: RESUMED状态时执行
lifecycleScope.launchWhenResumed {
// RESUMED状态时执行
// PAUSED状态时挂起
startAnimation()
}
// launchWhenCreated: CREATED状态及以上时执行
lifecycleScope.launchWhenCreated {
// 几乎立即执行
initializeData()
}
}
private suspend fun collectDataFlow() {
dataFlow.collect { data ->
println("Received: $data")
}
}
private suspend fun updateUI() {
delay(1000)
}
private suspend fun startAnimation() {
delay(1000)
}
private suspend fun initializeData() {
delay(1000)
}
private val dataFlow: Flow<String> = flow {
repeat(100) {
delay(1000)
emit("Data $it")
}
}
}
3.3 repeatOnLifecycle最佳实践
/**
* repeatOnLifecycle: 推荐的Flow收集方式
*/
class RepeatOnLifecycleExample : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ✅ 推荐: 使用repeatOnLifecycle
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
}
// ❌ 不推荐: 直接在lifecycleScope.launch中收集
// 问题: Activity在后台时仍然收集,浪费资源
lifecycleScope.launch {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
// ✅ 收集多个Flow
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
launch {
viewModel.events.collect { event ->
handleEvent(event)
}
}
launch {
viewModel.errors.collect { error ->
showError(error)
}
}
}
}
}
private fun updateUI(state: UiState) {}
private fun handleEvent(event: Event) {}
private fun showError(error: String) {}
}
class MyViewModel : ViewModel() {
val uiState = MutableStateFlow(UiState())
val events = MutableSharedFlow<Event>()
val errors = MutableSharedFlow<String>()
}
data class UiState(val loading: Boolean = false)
sealed class Event
3.4 Fragment中使用
/**
* Fragment中的lifecycleScope
*/
class MyFragment : Fragment() {
private var _binding: FragmentMyBinding? = null
private val binding get() = _binding!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// ⚠️ 注意: Fragment有两个生命周期
// 1. Fragment自己的生命周期
// 2. Fragment View的生命周期
// ✅ 推荐: 使用viewLifecycleOwner
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
// View重建时会重新执行
collectData()
}
}
// ❌ 不推荐: 使用Fragment的lifecycleScope
// 问题: Fragment被detach后协程仍在运行
lifecycleScope.launch {
collectData()
}
}
private suspend fun collectData() {
dataFlow.collect { data ->
binding.textView.text = data
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private val dataFlow: Flow<String> = flow {
emit("Data")
}
}
4. viewModelScope
4.1 viewModelScope基础
/**
* viewModelScope: ViewModel的协程作用域
*
* 特点:
* - ViewModel清除时自动取消
* - 配置改变时不会取消
* - 适合长生命周期任务
*/
class ViewModelScopeBasics : ViewModel() {
private val _data = MutableStateFlow<String>("")
val data: StateFlow<String> = _data.asStateFlow()
private val _loading = MutableStateFlow(false)
val loading: StateFlow<Boolean> = _loading.asStateFlow()
private val _error = MutableSharedFlow<String>()
val error: SharedFlow<String> = _error.asSharedFlow()
// 基础用法
fun loadData() {
viewModelScope.launch {
_loading.value = true
try {
val result = fetchData()
_data.value = result
} catch (e: Exception) {
_error.emit("加载失败: ${e.message}")
} finally {
_loading.value = false
}
}
}
// 并发任务
fun loadMultipleData() {
viewModelScope.launch {
_loading.value = true
try {
coroutineScope {
val data1 = async { fetchData1() }
val data2 = async { fetchData2() }
val data3 = async { fetchData3() }
val results = listOf(
data1.await(),
data2.await(),
data3.await()
)
_data.value = results.joinToString()
}
} catch (e: Exception) {
_error.emit("加载失败: ${e.message}")
} finally {
_loading.value = false
}
}
}
// 后台任务
fun startBackgroundSync() {
viewModelScope.launch {
while (isActive) {
syncData()
delay(60_000) // 每分钟同步一次
}
}
}
private suspend fun fetchData(): String {
delay(1000)
return "Data"
}
private suspend fun fetchData1(): String = "Data1"
private suspend fun fetchData2(): String = "Data2"
private suspend fun fetchData3(): String = "Data3"
private suspend fun syncData() {}
}
4.2 配置改变时的行为
/**
* viewModelScope在配置改变时的行为
*/
class ConfigChangeExample {
// ViewModel
class MyViewModel : ViewModel() {
init {
viewModelScope.launch {
println("ViewModel coroutine started")
repeat(10) {
delay(1000)
println("Tick $it")
}
println("ViewModel coroutine finished")
}
}
override fun onCleared() {
println("ViewModel cleared")
super.onCleared()
}
}
// Activity
class MyActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
println("Activity onCreate")
// 旋转屏幕:
// 1. Activity被销毁并重建
// 2. ViewModel不会被清除
// 3. viewModelScope中的协程继续运行
// 按返回键:
// 1. Activity被finish
// 2. ViewModel被清除
// 3. viewModelScope中的协程被取消
}
}
}
4.3 长时间运行的任务
/**
* viewModelScope中的长时间任务
*/
class LongRunningTaskExample : ViewModel() {
private val _progress = MutableStateFlow(0)
val progress: StateFlow<Int> = _progress.asStateFlow()
// 下载任务
fun downloadFile(url: String) {
viewModelScope.launch {
try {
downloadWithProgress(url) { progress ->
_progress.value = progress
}
} catch (e: CancellationException) {
println("Download cancelled")
throw e
} catch (e: Exception) {
println("Download failed: ${e.message}")
}
}
}
private suspend fun downloadWithProgress(
url: String,
onProgress: (Int) -> Unit
) {
repeat(100) { i ->
if (!isActive) return
delay(100)
onProgress(i + 1)
}
}
// 数据同步任务
private var syncJob: Job? = null
fun startSync() {
syncJob = viewModelScope.launch {
while (isActive) {
try {
syncData()
delay(300_000) // 5分钟
} catch (e: Exception) {
println("Sync failed: ${e.message}")
delay(60_000) // 失败后1分钟重试
}
}
}
}
fun stopSync() {
syncJob?.cancel()
syncJob = null
}
private suspend fun syncData() {}
}
4.4 与Repository协作
/**
* ViewModel + Repository模式
*/
class ViewModelRepositoryExample {
// Repository
class UserRepository @Inject constructor(
private val api: ApiService,
private val database: UserDatabase
) {
// Repository中的suspend函数
suspend fun getUser(userId: String): User {
return withContext(Dispatchers.IO) {
try {
val user = api.getUser(userId)
database.userDao().insert(user)
user
} catch (e: IOException) {
database.userDao().getUser(userId)
?: throw e
}
}
}
// Repository中的Flow
fun observeUser(userId: String): Flow<User> {
return database.userDao()
.observeUser(userId)
.flowOn(Dispatchers.IO)
}
}
// ViewModel
class UserViewModel @Inject constructor(
private val repository: UserRepository,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
private val userId: String
get() = savedStateHandle.get<String>("user_id") ?: ""
private val _user = MutableStateFlow<User?>(null)
val user: StateFlow<User?> = _user.asStateFlow()
init {
loadUser()
observeUser()
}
// 一次性加载
private fun loadUser() {
viewModelScope.launch {
try {
val user = repository.getUser(userId)
_user.value = user
} catch (e: Exception) {
Timber.e(e, "Failed to load user")
}
}
}
// 持续观察
private fun observeUser() {
viewModelScope.launch {
repository.observeUser(userId)
.catch { e ->
Timber.e(e, "Failed to observe user")
}
.collect { user ->
_user.value = user
}
}
}
// 更新用户
fun updateUser(name: String) {
viewModelScope.launch {
try {
val updatedUser = user.value?.copy(name = name)
?: return@launch
repository.updateUser(updatedUser)
} catch (e: Exception) {
Timber.e(e, "Failed to update user")
}
}
}
}
}
data class User(val id: String, val name: String)
interface ApiService {
suspend fun getUser(userId: String): User
}
interface UserDatabase {
fun userDao(): UserDao
}
interface UserDao {
suspend fun insert(user: User)
suspend fun getUser(userId: String): User?
fun observeUser(userId: String): Flow<User>
}
interface UserRepository {
suspend fun updateUser(user: User)
}
5. 自定义作用域
5.1 创建自定义作用域
/**
* 自定义协程作用域
*/
class CustomScopeExample {
// 方式1: 实现CoroutineScope接口
class MyComponent : CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
fun doWork() {
launch {
processData()
}
}
fun cleanup() {
job.cancel()
}
private suspend fun processData() {
delay(1000)
}
}
// 方式2: 使用委托
class AnotherComponent {
private val scope = CoroutineScope(
SupervisorJob() + Dispatchers.Main
)
fun doWork() {
scope.launch {
processData()
}
}
fun cleanup() {
scope.cancel()
}
private suspend fun processData() {
delay(1000)
}
}
// 方式3: MainScope
class SimpleComponent {
private val scope = MainScope()
fun doWork() {
scope.launch {
processData()
}
}
fun cleanup() {
scope.cancel()
}
private suspend fun processData() {
delay(1000)
}
}
}
5.2 配置自定义作用域
/**
* 自定义作用域的配置
*/
class ScopeConfiguration {
// 基础配置
class BasicScope : CoroutineScope {
override val coroutineContext = Job() + Dispatchers.Main
}
// 使用SupervisorJob
class SupervisorScope : CoroutineScope {
override val coroutineContext = SupervisorJob() + Dispatchers.Main
// 子协程异常不会影响其他子协程
}
// 添加异常处理
class ExceptionHandlingScope : CoroutineScope {
private val exceptionHandler = CoroutineExceptionHandler { _, exception ->
Timber.e(exception, "Coroutine failed")
}
override val coroutineContext =
SupervisorJob() +
Dispatchers.Main +
exceptionHandler +
CoroutineName("MyScope")
}
// 自定义调度器
class CustomDispatcherScope : CoroutineScope {
private val customDispatcher = Executors.newFixedThreadPool(4)
.asCoroutineDispatcher()
override val coroutineContext =
SupervisorJob() + customDispatcher
fun cleanup() {
coroutineContext.cancel()
customDispatcher.close()
}
}
// 限制并发数
class LimitedScope : CoroutineScope {
override val coroutineContext =
SupervisorJob() +
Dispatchers.IO.limitedParallelism(2)
// 最多2个任务同时运行
}
}
5.3 作用域的生命周期管理
/**
* 自定义作用域的生命周期管理
*/
class ScopeLifecycleManagement {
// Repository作用域
@Singleton
class DataRepository @Inject constructor(
private val api: ApiService,
private val database: AppDatabase
) : CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext = job + Dispatchers.IO
// 预加载数据
init {
launch {
preloadData()
}
}
// 后台同步
private var syncJob: Job? = null
fun startBackgroundSync() {
syncJob = launch {
while (isActive) {
try {
syncData()
delay(300_000)
} catch (e: Exception) {
Timber.e(e, "Sync failed")
delay(60_000)
}
}
}
}
fun stopBackgroundSync() {
syncJob?.cancel()
}
// 清理
fun cleanup() {
stopBackgroundSync()
job.cancel()
}
private suspend fun preloadData() {}
private suspend fun syncData() {}
}
// Service作用域
class MyService : Service(), CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext = job + Dispatchers.Main
override fun onCreate() {
super.onCreate()
launch {
doWork()
}
}
override fun onDestroy() {
job.cancel()
super.onDestroy()
}
private suspend fun doWork() {}
override fun onBind(intent: Intent?): IBinder? = null
}
// Application作用域
class MyApplication : Application(), CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext = job + Dispatchers.Main
override fun onCreate() {
super.onCreate()
launch {
initializeApp()
}
}
override fun onTerminate() {
job.cancel()
super.onTerminate()
}
private suspend fun initializeApp() {}
}
}
6. 生命周期管理
6.1 作用域取消
/**
* 协程作用域的取消
*/
class ScopeCancellation {
// 手动取消
fun manualCancellation() {
val scope = CoroutineScope(Job())
scope.launch {
try {
repeat(100) {
delay(100)
println("Working $it")
}
} catch (e: CancellationException) {
println("Cancelled")
}
}
Thread.sleep(550)
scope.cancel() // 取消作用域
}
// 取消并等待
suspend fun cancelAndJoin() {
val scope = CoroutineScope(Job())
val job = scope.launch {
try {
delay(Long.MAX_VALUE)
} finally {
withContext(NonCancellable) {
println("Cleanup")
delay(1000)
println("Cleanup done")
}
}
}
delay(500)
job.cancelAndJoin() // 取消并等待清理完成
println("Job cancelled and joined")
}
// 检查取消状态
fun checkCancellation() {
val scope = CoroutineScope(Job())
scope.launch {
while (isActive) {
// 定期检查是否被取消
doWorkItem()
}
println("Coroutine finished")
}
}
private fun doWorkItem() {}
}
6.2 作用域清理
/**
* 协程作用域的资源清理
*/
class ScopeCleanup {
class ResourceManager : CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext = job + Dispatchers.IO
private val resources = mutableListOf<Resource>()
fun acquireResource(): Resource {
val resource = Resource()
resources.add(resource)
launch {
try {
resource.use()
} finally {
// 清理资源
withContext(NonCancellable) {
resource.cleanup()
resources.remove(resource)
}
}
}
return resource
}
fun cleanup() {
// 取消所有协程
job.cancel()
// 清理所有资源
resources.forEach { it.cleanup() }
resources.clear()
}
class Resource {
suspend fun use() {
delay(Long.MAX_VALUE)
}
fun cleanup() {
println("Resource cleaned up")
}
}
}
// 嵌套作用域清理
suspend fun nestedCleanup() = coroutineScope {
val resource1 = acquireResource()
try {
coroutineScope {
val resource2 = acquireResource()
try {
useResources(resource1, resource2)
} finally {
resource2.cleanup()
}
}
} finally {
resource1.cleanup()
}
}
private fun acquireResource(): Resource = Resource()
private suspend fun useResources(r1: Resource, r2: Resource) {}
class Resource {
fun cleanup() {}
}
}
6.3 作用域超时
/**
* 协程作用域的超时控制
*/
class ScopeTimeout {
// withTimeout: 超时抛异常
suspend fun strictTimeout() {
try {
withTimeout(1000) {
repeat(100) {
delay(100)
println("Working $it")
}
}
} catch (e: TimeoutCancellationException) {
println("Timeout!")
}
}
// withTimeoutOrNull: 超时返回null
suspend fun softTimeout() {
val result = withTimeoutOrNull(1000) {
delay(2000)
"Result"
}
if (result == null) {
println("Timeout!")
} else {
println("Got: $result")
}
}
// 自定义超时处理
suspend fun customTimeout() {
val scope = CoroutineScope(Job())
val job = scope.launch {
try {
processLongTask()
} catch (e: CancellationException) {
println("Task cancelled due to timeout")
}
}
// 10秒后超时
launch {
delay(10_000)
if (job.isActive) {
job.cancel()
}
}
job.join()
}
private suspend fun processLongTask() {
delay(Long.MAX_VALUE)
}
}
7. 作用域传播
7.1 父子作用域关系
/**
* 作用域的父子关系
*/
class ScopePropagation {
// 父作用域等待子作用域
suspend fun parentWaitsChildren() = coroutineScope {
launch {
delay(1000)
println("Child 1 done")
}
launch {
delay(2000)
println("Child 2 done")
}
println("Parent waiting...")
// coroutineScope会等待所有子协程完成
}
// 父作用域取消传播到子作用域
suspend fun parentCancelsChildren() {
val parentScope = CoroutineScope(Job())
parentScope.launch {
launch {
try {
delay(Long.MAX_VALUE)
} catch (e: CancellationException) {
println("Child 1 cancelled")
}
}
launch {
try {
delay(Long.MAX_VALUE)
} catch (e: CancellationException) {
println("Child 2 cancelled")
}
}
delay(1000)
}
delay(500)
parentScope.cancel()
println("Parent cancelled, all children cancelled")
}
// 子作用域异常传播到父作用域
suspend fun childExceptionPropagatesToParent() {
try {
coroutineScope {
launch {
delay(500)
throw RuntimeException("Child failed")
}
launch {
delay(1000)
println("Won't execute")
}
}
} catch (e: Exception) {
println("Caught: ${e.message}")
}
}
}
7.2 supervisorScope隔离
/**
* supervisorScope: 子协程失败不影响其他子协程
*/
class SupervisorScopeExample {
// 独立失败
suspend fun independentFailures() = supervisorScope {
val job1 = launch {
try {
delay(500)
throw RuntimeException("Job 1 failed")
} catch (e: Exception) {
println("Job 1 error: ${e.message}")
}
}
val job2 = launch {
delay(1000)
println("Job 2 completed")
}
val job3 = launch {
delay(1500)
println("Job 3 completed")
}
// job1失败不会取消job2和job3
}
// 多个独立任务
suspend fun multipleIndependentTasks() = supervisorScope {
val tasks = listOf("Task1", "Task2", "Task3", "Task4", "Task5")
tasks.forEach { task ->
launch {
try {
processTask(task)
} catch (e: Exception) {
println("$task failed: ${e.message}")
}
}
}
}
private suspend fun processTask(task: String) {
delay(1000)
if (task == "Task2") {
throw RuntimeException("Failed")
}
println("$task completed")
}
// SupervisorJob
class WorkerManager {
private val scope = CoroutineScope(
SupervisorJob() + Dispatchers.Default
)
fun startWorkers(count: Int) {
repeat(count) { workerId ->
scope.launch {
try {
workerTask(workerId)
} catch (e: Exception) {
println("Worker $workerId failed: ${e.message}")
}
}
}
}
private suspend fun workerTask(workerId: Int) {
while (isActive) {
delay(1000)
println("Worker $workerId working")
if (workerId == 2) {
throw RuntimeException("Worker 2 error")
}
}
}
fun shutdown() {
scope.cancel()
}
}
}
8. deviceSecurity实战案例
8.1 案例1: 设备管理器生命周期
/**
* 场景: deviceSecurity设备管理器
*
* 需求:
* 1. 管理所有设备的协程
* 2. 支持单个设备的独立管理
* 3. 应用退出时清理所有资源
*/
@Singleton
class DeviceManager @Inject constructor(
private val deviceRepository: DeviceRepository,
private val connectionManager: ConnectionManager,
@ApplicationContext private val context: Context
) : CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext = job + Dispatchers.Main
private val deviceScopes = mutableMapOf<String, Job>()
init {
// 启动设备发现
launch {
startDeviceDiscovery()
}
// 启动心跳检测
launch {
startHeartbeat()
}
}
/**
* 开始管理设备
*/
fun manageDevice(deviceId: String) {
// 如果已经在管理,先停止
stopManagingDevice(deviceId)
// 创建新的Job
val deviceJob = launch {
try {
// 连接设备
connectionManager.connect(deviceId)
// 启动状态监控
launch {
monitorDeviceStatus(deviceId)
}
// 启动数据同步
launch {
syncDeviceData(deviceId)
}
// 启动事件监听
launch {
listenDeviceEvents(deviceId)
}
} catch (e: CancellationException) {
Timber.d("Device $deviceId management cancelled")
throw e
} catch (e: Exception) {
Timber.e(e, "Failed to manage device $deviceId")
} finally {
withContext(NonCancellable) {
// 断开连接
connectionManager.disconnect(deviceId)
deviceScopes.remove(deviceId)
}
}
}
deviceScopes[deviceId] = deviceJob
}
/**
* 停止管理设备
*/
fun stopManagingDevice(deviceId: String) {
deviceScopes[deviceId]?.cancel()
deviceScopes.remove(deviceId)
}
/**
* 设备发现
*/
private suspend fun startDeviceDiscovery() {
while (isActive) {
try {
val devices = deviceRepository.discoverDevices()
devices.forEach { device ->
if (device.id !in deviceScopes) {
manageDevice(device.id)
}
}
} catch (e: Exception) {
Timber.e(e, "Device discovery failed")
}
delay(30_000) // 30秒扫描一次
}
}
/**
* 心跳检测
*/
private suspend fun startHeartbeat() {
while (isActive) {
try {
deviceScopes.keys.forEach { deviceId ->
launch {
connectionManager.sendHeartbeat(deviceId)
}
}
} catch (e: Exception) {
Timber.e(e, "Heartbeat failed")
}
delay(10_000) // 10秒发送一次心跳
}
}
/**
* 监控设备状态
*/
private suspend fun monitorDeviceStatus(deviceId: String) {
deviceRepository.observeDeviceStatus(deviceId)
.catch { e ->
Timber.e(e, "Failed to monitor device $deviceId")
}
.collect { status ->
handleDeviceStatus(deviceId, status)
}
}
/**
* 同步设备数据
*/
private suspend fun syncDeviceData(deviceId: String) {
while (isActive) {
try {
val data = connectionManager.fetchDeviceData(deviceId)
deviceRepository.saveDeviceData(deviceId, data)
} catch (e: Exception) {
Timber.e(e, "Failed to sync device $deviceId")
}
delay(60_000) // 1分钟同步一次
}
}
/**
* 监听设备事件
*/
private suspend fun listenDeviceEvents(deviceId: String) {
connectionManager.observeDeviceEvents(deviceId)
.catch { e ->
Timber.e(e, "Failed to listen events from device $deviceId")
}
.collect { event ->
handleDeviceEvent(deviceId, event)
}
}
/**
* 处理设备状态
*/
private suspend fun handleDeviceStatus(deviceId: String, status: DeviceStatus) {
// 更新数据库
deviceRepository.updateDeviceStatus(deviceId, status)
// 检查异常状态
if (status.isAbnormal) {
// 发送通知
sendNotification(deviceId, "设备异常")
}
}
/**
* 处理设备事件
*/
private suspend fun handleDeviceEvent(deviceId: String, event: DeviceEvent) {
when (event) {
is DeviceEvent.MotionDetected -> {
// 运动检测
sendNotification(deviceId, "检测到移动")
}
is DeviceEvent.BatteryLow -> {
// 电量低
sendNotification(deviceId, "电量低")
}
is DeviceEvent.ConnectionLost -> {
// 连接丢失
stopManagingDevice(deviceId)
}
}
}
/**
* 发送通知
*/
private fun sendNotification(deviceId: String, message: String) {
// 发送系统通知
}
/**
* 清理
*/
fun cleanup() {
// 停止所有设备管理
deviceScopes.keys.toList().forEach { deviceId ->
stopManagingDevice(deviceId)
}
// 取消所有协程
job.cancel()
}
}
interface ConnectionManager {
suspend fun connect(deviceId: String)
suspend fun disconnect(deviceId: String)
suspend fun sendHeartbeat(deviceId: String)
suspend fun fetchDeviceData(deviceId: String): DeviceData
fun observeDeviceEvents(deviceId: String): Flow<DeviceEvent>
}
interface DeviceRepository {
suspend fun discoverDevices(): List<Device>
fun observeDeviceStatus(deviceId: String): Flow<DeviceStatus>
suspend fun saveDeviceData(deviceId: String, data: DeviceData)
suspend fun updateDeviceStatus(deviceId: String, status: DeviceStatus)
}
data class Device(val id: String, val name: String)
data class DeviceData(val timestamp: Long, val data: String)
data class DeviceStatus(val isOnline: Boolean, val battery: Int) {
val isAbnormal: Boolean = battery < 20 || !isOnline
}
sealed class DeviceEvent {
object MotionDetected : DeviceEvent()
object BatteryLow : DeviceEvent()
object ConnectionLost : DeviceEvent()
}
8.2 案例2: 视频下载管理器
/**
* 场景: deviceSecurity视频下载管理器
*
* 需求:
* 1. 支持多个视频同时下载
* 2. 限制并发下载数量
* 3. 支持暂停/恢复/取消
*/
@Singleton
class VideoDownloadManager @Inject constructor(
private val videoRepository: VideoRepository,
private val storageManager: StorageManager
) : CoroutineScope {
private val job = SupervisorJob()
// 限制最多3个同时下载
private val limitedDispatcher = Dispatchers.IO.limitedParallelism(3)
override val coroutineContext = job + limitedDispatcher
private val downloadJobs = mutableMapOf<String, Job>()
private val _downloads = MutableStateFlow<Map<String, DownloadState>>(emptyMap())
val downloads: StateFlow<Map<String, DownloadState>> = _downloads.asStateFlow()
/**
* 开始下载
*/
fun download(videoId: String, url: String) {
// 如果已经在下载,忽略
if (videoId in downloadJobs) {
return
}
// 更新状态为下载中
updateDownloadState(videoId, DownloadState.Downloading(0))
// 启动下载协程
val downloadJob = launch {
try {
downloadVideo(videoId, url)
updateDownloadState(videoId, DownloadState.Completed)
} catch (e: CancellationException) {
updateDownloadState(videoId, DownloadState.Cancelled)
throw e
} catch (e: Exception) {
updateDownloadState(videoId, DownloadState.Failed(e.message ?: "下载失败"))
} finally {
downloadJobs.remove(videoId)
}
}
downloadJobs[videoId] = downloadJob
}
/**
* 下载视频
*/
private suspend fun downloadVideo(videoId: String, url: String) {
// 检查存储空间
if (!storageManager.hasEnoughSpace()) {
throw IOException("存储空间不足")
}
// 创建临时文件
val tempFile = storageManager.createTempFile(videoId)
try {
// 下载数据
videoRepository.downloadVideo(url) { progress ->
updateDownloadState(videoId, DownloadState.Downloading(progress))
}.collect { chunk ->
// 写入文件
tempFile.appendBytes(chunk)
}
// 移动到最终位置
val finalFile = storageManager.moveToFinalLocation(videoId, tempFile)
// 保存到数据库
videoRepository.saveVideoFile(videoId, finalFile.absolutePath)
} catch (e: Exception) {
// 删除临时文件
tempFile.delete()
throw e
}
}
/**
* 暂停下载
*/
fun pause(videoId: String) {
downloadJobs[videoId]?.cancel()
downloadJobs.remove(videoId)
updateDownloadState(videoId, DownloadState.Paused)
}
/**
* 恢复下载
*/
fun resume(videoId: String, url: String) {
// 重新开始下载
download(videoId, url)
}
/**
* 取消下载
*/
fun cancel(videoId: String) {
downloadJobs[videoId]?.cancel()
downloadJobs.remove(videoId)
updateDownloadState(videoId, DownloadState.Cancelled)
// 删除临时文件
launch {
storageManager.deleteTempFile(videoId)
}
}
/**
* 取消所有下载
*/
fun cancelAll() {
downloadJobs.keys.toList().forEach { videoId ->
cancel(videoId)
}
}
/**
* 更新下载状态
*/
private fun updateDownloadState(videoId: String, state: DownloadState) {
_downloads.value = _downloads.value.toMutableMap().apply {
put(videoId, state)
}
}
/**
* 清理
*/
fun cleanup() {
cancelAll()
job.cancel()
}
}
/**
* 下载状态
*/
sealed class DownloadState {
data class Downloading(val progress: Int) : DownloadState()
object Paused : DownloadState()
object Completed : DownloadState()
object Cancelled : DownloadState()
data class Failed(val message: String) : DownloadState()
}
interface VideoRepository {
fun downloadVideo(url: String, onProgress: (Int) -> Unit): Flow<ByteArray>
suspend fun saveVideoFile(videoId: String, filePath: String)
}
interface StorageManager {
fun hasEnoughSpace(): Boolean
fun createTempFile(videoId: String): File
fun moveToFinalLocation(videoId: String, tempFile: File): File
suspend fun deleteTempFile(videoId: String)
}
8.3 案例3: 实时事件流处理
/**
* 场景: deviceSecurity实时事件流处理
*
* 需求:
* 1. 处理多个设备的实时事件
* 2. 根据Activity生命周期启停
* 3. 事件优先级处理
*/
class EventStreamViewModel @Inject constructor(
private val eventRepository: EventRepository,
private val notificationManager: NotificationManager
) : ViewModel() {
private val _events = MutableSharedFlow<DeviceEvent>(
replay = 10,
extraBufferCapacity = 100
)
val events: SharedFlow<DeviceEvent> = _events.asSharedFlow()
private val _highPriorityEvents = MutableSharedFlow<DeviceEvent>()
val highPriorityEvents: SharedFlow<DeviceEvent> = _highPriorityEvents.asSharedFlow()
private var streamJob: Job? = null
/**
* 开始监听事件流
*/
fun startListening(deviceIds: List<String>) {
streamJob?.cancel()
streamJob = viewModelScope.launch {
supervisorScope {
// 为每个设备创建独立的监听
deviceIds.forEach { deviceId ->
launch {
listenDeviceEvents(deviceId)
}
}
// 处理高优先级事件
launch {
processHighPriorityEvents()
}
}
}
}
/**
* 停止监听
*/
fun stopListening() {
streamJob?.cancel()
streamJob = null
}
/**
* 监听单个设备的事件
*/
private suspend fun listenDeviceEvents(deviceId: String) {
eventRepository.observeDeviceEvents(deviceId)
.catch { e ->
Timber.e(e, "Failed to listen events from device $deviceId")
// 错误不会取消其他设备的监听
}
.collect { event ->
// 发送到事件流
_events.emit(event)
// 高优先级事件单独处理
if (event.isHighPriority) {
_highPriorityEvents.emit(event)
}
}
}
/**
* 处理高优先级事件
*/
private suspend fun processHighPriorityEvents() {
_highPriorityEvents.collect { event ->
when (event) {
is DeviceEvent.MotionDetected -> {
// 立即发送通知
notificationManager.sendNotification(
title = "检测到移动",
message = "设备 ${event.deviceId} 检测到移动"
)
// 开始录制
eventRepository.startRecording(event.deviceId)
}
is DeviceEvent.BatteryLow -> {
// 发送电量低通知
notificationManager.sendNotification(
title = "电量低",
message = "设备 ${event.deviceId} 电量低于 ${event.battery}%"
)
}
is DeviceEvent.ConnectionLost -> {
// 发送连接丢失通知
notificationManager.sendNotification(
title = "连接丢失",
message = "设备 ${event.deviceId} 连接丢失"
)
}
}
}
}
}
/**
* Activity中使用
*/
class EventStreamActivity : AppCompatActivity() {
private val viewModel: EventStreamViewModel by viewModels()
private lateinit var binding: ActivityEventStreamBinding
private val adapter = EventAdapter()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityEventStreamBinding.inflate(layoutInflater)
setContentView(binding.root)
setupRecyclerView()
observeEvents()
}
private fun setupRecyclerView() {
binding.recyclerView.apply {
layoutManager = LinearLayoutManager(this@EventStreamActivity)
adapter = this@EventStreamActivity.adapter
}
}
private fun observeEvents() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
// STARTED时开始监听
viewModel.startListening(getDeviceIds())
// 收集事件
launch {
viewModel.events.collect { event ->
adapter.addEvent(event)
binding.recyclerView.smoothScrollToPosition(0)
}
}
// 收集高优先级事件
launch {
viewModel.highPriorityEvents.collect { event ->
showHighPriorityAlert(event)
}
}
}
// STOPPED时停止监听
viewModel.stopListening()
}
}
private fun getDeviceIds(): List<String> {
// 获取设备ID列表
return listOf("device1", "device2", "device3")
}
private fun showHighPriorityAlert(event: DeviceEvent) {
MaterialAlertDialogBuilder(this)
.setTitle("紧急事件")
.setMessage(event.toString())
.setPositiveButton("确定", null)
.show()
}
}
interface EventRepository {
fun observeDeviceEvents(deviceId: String): Flow<DeviceEvent>
suspend fun startRecording(deviceId: String)
}
interface NotificationManager {
fun sendNotification(title: String, message: String)
}
val DeviceEvent.isHighPriority: Boolean
get() = this is DeviceEvent.MotionDetected || this is DeviceEvent.BatteryLow
val DeviceEvent.deviceId: String
get() = when (this) {
is DeviceEvent.MotionDetected -> "deviceId"
is DeviceEvent.BatteryLow -> "deviceId"
is DeviceEvent.ConnectionLost -> "deviceId"
}
val DeviceEvent.BatteryLow.battery: Int
get() = 10
class EventAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val events = mutableListOf<DeviceEvent>()
fun addEvent(event: DeviceEvent) {
events.add(0, event)
notifyItemInserted(0)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
TODO()
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
TODO()
}
override fun getItemCount(): Int = events.size
}
9. 最佳实践
9.1 选择合适的作用域
/**
* 最佳实践: 选择合适的协程作用域
*/
class ScopeSelection {
// ✅ 推荐: Activity/Fragment使用lifecycleScope
class MyActivity : AppCompatActivity() {
fun loadData() {
lifecycleScope.launch {
// Activity销毁时自动取消
val data = fetchData()
updateUI(data)
}
}
private suspend fun fetchData(): String = "Data"
private fun updateUI(data: String) {}
}
// ✅ 推荐: ViewModel使用viewModelScope
class MyViewModel : ViewModel() {
fun loadData() {
viewModelScope.launch {
// ViewModel清除时自动取消
// 配置改变时不会取消
processData()
}
}
private suspend fun processData() {}
}
// ✅ 推荐: Repository使用自定义作用域
@Singleton
class MyRepository : CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext = job + Dispatchers.IO
fun cleanup() {
job.cancel()
}
}
// ❌ 不推荐: 使用GlobalScope
class BadExample {
fun doWork() {
GlobalScope.launch {
// 无法控制生命周期
}
}
}
}
9.2 正确使用repeatOnLifecycle
/**
* 最佳实践: 正确使用repeatOnLifecycle
*/
class RepeatOnLifecycleBestPractice : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ✅ 推荐: 使用repeatOnLifecycle收集Flow
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
}
// ✅ 推荐: 收集多个Flow
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.uiState.collect { updateUI(it) }
}
launch {
viewModel.events.collect { handleEvent(it) }
}
}
}
// ❌ 不推荐: 直接在lifecycleScope中收集
// 问题: Activity在后台时仍然收集
lifecycleScope.launch {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
}
private fun updateUI(state: UiState) {}
private fun handleEvent(event: Event) {}
}
9.3 正确管理作用域生命周期
/**
* 最佳实践: 正确管理作用域生命周期
*/
class ScopeLifecycleManagement {
// ✅ 推荐: Service中管理作用域
class MyService : Service(), CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext = job + Dispatchers.Main
override fun onCreate() {
super.onCreate()
launch {
doWork()
}
}
override fun onDestroy() {
job.cancel() // 取消所有协程
super.onDestroy()
}
private suspend fun doWork() {}
override fun onBind(intent: Intent?): IBinder? = null
}
// ✅ 推荐: 自定义组件管理作用域
class MyComponent : CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext = job + Dispatchers.Main
fun start() {
launch {
doWork()
}
}
fun stop() {
job.cancel()
}
private suspend fun doWork() {}
}
// ❌ 不推荐: 忘记清理作用域
class BadComponent {
private val scope = CoroutineScope(Job())
fun start() {
scope.launch {
// 永远不会被取消
delay(Long.MAX_VALUE)
}
}
// 缺少cleanup方法
}
}
10. 常见问题FAQ
Q1: GlobalScope和自定义作用域有什么区别?
A:
- GlobalScope: 全局作用域,生命周期是整个应用,无法控制
- 自定义作用域: 可以控制生命周期,可以手动取消
// GlobalScope - 无法控制
GlobalScope.launch {
// 一直运行直到应用关闭
}
// 自定义作用域 - 可以控制
val scope = CoroutineScope(Job())
scope.launch {
// 工作
}
scope.cancel() // 可以取消
Q2: lifecycleScope和viewModelScope的区别?
A:
- lifecycleScope: 绑定到Activity/Fragment生命周期,配置改变时会取消
- viewModelScope: 绑定到ViewModel生命周期,配置改变时不会取消
// lifecycleScope - 配置改变时取消
class MyActivity : AppCompatActivity() {
fun loadData() {
lifecycleScope.launch {
// 旋转屏幕时会取消
}
}
}
// viewModelScope - 配置改变时不取消
class MyViewModel : ViewModel() {
fun loadData() {
viewModelScope.launch {
// 旋转屏幕时不会取消
}
}
}
Q3: repeatOnLifecycle有什么用?
A: 在指定生命周期状态重复执行,主要用于收集Flow
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
// STARTED状态时执行
// STOPPED状态时取消
// 再次STARTED时重新执行
viewModel.data.collect { data ->
updateUI(data)
}
}
}
Q4: SupervisorJob和普通Job的区别?
A:
- 普通Job: 子协程失败会取消所有兄弟协程
- SupervisorJob: 子协程失败不影响其他子协程
// 普通Job
coroutineScope {
launch { throw Exception() } // 失败
launch { println("Won't execute") } // 被取消
}
// SupervisorJob
supervisorScope {
launch { throw Exception() } // 失败
launch { println("Will execute") } // 继续执行
}
Q5: 如何在Fragment中正确使用作用域?
A: 使用viewLifecycleOwner.lifecycleScope
class MyFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// ✅ 正确
viewLifecycleOwner.lifecycleScope.launch {
// View销毁时取消
}
// ❌ 错误
lifecycleScope.launch {
// Fragment detach时不会取消
}
}
}
Q6: 作用域取消后还能再次使用吗?
A: 不能,作用域取消后无法再次使用,需要创建新的作用域
val scope = CoroutineScope(Job())
scope.cancel()
scope.launch {
// 不会执行!
}
// 需要创建新的作用域
val newScope = CoroutineScope(Job())
newScope.launch {
// 可以执行
}
Q7: 如何等待作用域中所有协程完成?
A: 使用coroutineScope或保存Job并join
// 方式1: coroutineScope
suspend fun waitAll() = coroutineScope {
launch { task1() }
launch { task2() }
// 自动等待所有协程完成
}
// 方式2: join
fun waitAll2() {
val scope = CoroutineScope(Job())
val job1 = scope.launch { task1() }
val job2 = scope.launch { task2() }
runBlocking {
job1.join()
job2.join()
}
}
Q8: 如何在作用域中处理异常?
A: 使用CoroutineExceptionHandler或try-catch
// 方式1: ExceptionHandler
val handler = CoroutineExceptionHandler { _, e ->
println("Caught: $e")
}
val scope = CoroutineScope(SupervisorJob() + handler)
// 方式2: try-catch
scope.launch {
try {
doWork()
} catch (e: Exception) {
println("Caught: $e")
}
}
Q9: 什么时候使用supervisorScope?
A: 当子任务相互独立,一个失败不应影响其他时
supervisorScope {
// 并发下载多个文件
files.forEach { file ->
launch {
try {
downloadFile(file)
} catch (e: Exception) {
println("$file failed")
}
}
}
// 一个文件下载失败不影响其他文件
}
Q10: 如何调试作用域问题?
A:
- 启用协程调试: -Dkotlinx.coroutines.debug
- 使用CoroutineName
- 检查作用域生命周期
- 使用Timber记录日志
val scope = CoroutineScope(
Job() +
Dispatchers.Main +
CoroutineName("MyScope")
)
scope.launch {
Timber.d("Running in ${coroutineContext[CoroutineName]}")
}
总结
本文全面介绍了协程作用域与生命周期管理:
核心概念
- 作用域类型: GlobalScope, lifecycleScope, viewModelScope, 自定义作用域
- 生命周期: 创建、运行、取消、清理
- 作用域传播: 父子关系、取消传播、异常传播
- supervisorScope: 隔离子协程失败
关键要点
- 避免使用GlobalScope,使用生命周期感知的作用域
- Activity/Fragment使用lifecycleScope
- ViewModel使用viewModelScope
- 自定义组件创建自己的作用域
- 使用repeatOnLifecycle收集Flow
- 使用supervisorScope隔离独立任务
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)