使用Kotlin协程递归创建目录时如何判断全部任务执行完成
解决方案
核心问题根因
你原有代码中所有子协程都通过lifecycleScope启动,属于全局生命周期作用域的子任务,和你初始调用createDirectoryStructure所在的协程没有父子绑定关系,因此外层协程不会等待这些子任务执行完成,就会继续往下执行后续代码。
最优修复方案
利用Kotlin协程结构化并发特性,使用coroutineScope包裹递归逻辑,该作用域会自动跟踪所有内部启动的子协程,只有全部子协程执行完成后,coroutineScope块才会返回,完全不需要手动维护计数器或者Job列表。
改后递归方法代码
// directoryBeingBuilt starts as the root directory private suspend fun createDirectoryStructure(directoryBeingBuiltId: String, directoryBeingBuiltUri: Uri) = coroutineScope { // Create subdirectories for all children of directoryBeingBuilt. directoryMap[directoryBeingBuiltId]?.forEach { childDirectory -> // Create a directory for each childDirectory and set its Uri in directoryMap. val currentSubdirectoryUri = getOrCreateDirectory(directoryBeingBuiltUri, childDirectory.directoryName)!! childDirectory.directoryUri = currentSubdirectoryUri // 直接在当前coroutineScope启动子协程,会被自动纳入作用域跟踪 launch(Dispatchers.Default) { createDirectoryStructure(childDirectory.directoryId, currentSubdirectoryUri) } } }
初始调用逻辑无需修改
withContext(Dispatchers.Default) { createDirectoryStructure(googleDriveRootDirectoryId.data, backupDirectoryUri) // 此处代码会在所有目录创建完成后自动执行 callYourMethodAfterFinish() }
原方案不可靠原因说明
- 计数器方案不可靠通常是因为没有使用线程安全的原子类(如
AtomicInteger)维护计数,或者计数增减的时机不对,存在可见性、竞态条件问题 - 手动维护Job列表的方案需要你每次launch后把Job存入列表,最后调用
joinAll()等待所有Job完成,实现繁琐且容易遗漏任务 - 完全不使用协程相当于串行执行IO操作,耗时自然翻倍,而
coroutineScope方案不会损失任何并行性能
内容的提问来源于stack exchange,提问作者Gavin Wright
相关产品推荐
相关产品推荐

