一键导入
android-coroutines-expert
Use to enforce safe concurrency, correct Dispatcher usage, and proper Channel vs StateFlow patterns in ViewModels.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use to enforce safe concurrency, correct Dispatcher usage, and proper Channel vs StateFlow patterns in ViewModels.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Handling Bluetooth Low Energy, flow wrappers, and Android 12+ permissions.
Seamless integration of CameraX with Google ML Kit for vision tasks.
Deep-dive skills for banking and healthcare apps.
Use when integrating Google Gemini Nano via AICore for on-device ML.
Automated UIAutomator tests and Hardware mocking setup.
Expanding KMP shared UI to cover Compose Multiplatform edge-cases.
| name | android-coroutines-expert |
| description | Use to enforce safe concurrency, correct Dispatcher usage, and proper Channel vs StateFlow patterns in ViewModels. |
| category | performance |
| risk | medium |
| source | community |
| date_added | 2026-03-31 |
| metadata | {"triggers":["@coroutines","concurrency","flow-vs-channel","viewmodelscope","dispatchers"]} |
A strict rulebook to prevent thread-blocking, memory leaks, and lost UI events in modern Android applications.
You must explicitly distinguish between UI State (things that persist on rotation) and UI Events (things that happen once, like a Toast or Navigation).
MutableStateFlow.Channel exported as a Flow. NEVER use SharedFlow with replay = 0 or MutableStateFlow for one-time events, because if the app rotates, the event might be dropped or replayed twice.The Golden Implementation:
class MyViewModel : ViewModel() {
// 1. UI STATE
private val _uiState = MutableStateFlow(MyState())
val uiState = _uiState.asStateFlow()
// 2. ONE-TIME EVENTS
private val _uiEvent = Channel<MyAction>()
val uiEvent = _uiEvent.receiveAsFlow()
fun triggerSnackbar() {
viewModelScope.launch {
_uiEvent.send(MyAction.ShowSnackbar)
}
}
}
Agents frequently launch heavy database or network calls on the default dispatcher (Dispatchers.Main inside a viewModelScope.launch).
viewModelScope.launch { } is fine.Dispatchers.IO using withContext(Dispatchers.IO) { ... }.Dispatchers.Default.If an agent executes multiple independent API requests inside a viewModelScope.launch, and one fails, it cancels the entire scope/parent job!
The Anti-Pattern:
viewModelScope.launch {
// If ApiA fails, ApiB is cancelled!
val resultA = apiA.fetch()
val resultB = apiB.fetch()
}
The Architect's Standard (supervisorScope or async):
viewModelScope.launch {
// Both attempt to run. If A fails, B continues successfully.
supervisorScope {
val deferredA = async { apiA.fetch() }
val deferredB = async { apiB.fetch() }
try { val a = deferredA.await() } catch (e: Exception) {}
try { val b = deferredB.await() } catch (e: Exception) {}
}
}
As enforced in our Code Review checklists, NEVER use collectAsState() in Compose UI. Always use collectAsStateWithLifecycle() to ensure Coroutines pause fetching when the screen goes to the background.