ワンクリックで
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.