
Kotlin Coroutines Flows
- 5.9k installs
- 238k repo stars
- Updated August 5, 2026
- affaan-m/everything-claude-code
kotlin-coroutines-flows is an agent skill that documents structured concurrency, Flow operators, StateFlow, SharedFlow, dispatchers, cancellation, and Turbine testing for Android and Kotlin Multiplatform.
About
This skill teaches Kotlin coroutines and Flow patterns for Android and Kotlin Multiplatform projects. It explains structured concurrency with viewModelScope, coroutineScope plus async for parallel repository loads, and supervisorScope when one child failure must not cancel siblings. Flow coverage spans cold flows, StateFlow with SharingStarted.WhileSubscribed, combining multiple repositories into one UI state, and operators for debounce, distinctUntilChanged, flatMapLatest, catch, and exponential retryWhen. SharedFlow carries one-time snackbar and navigation effects to Compose collectors. Dispatcher guidance maps CPU work to Default, blocking IO to IO on JVM and Android only, and UI updates to Main, with KMP notes where IO is unavailable. Cancellation sections require ensureActive in long loops, finally cleanup for loading flags, and never swallowing CancellationException. Testing recipes use Turbine awaitItem assertions, runTest with advanceUntilIdle, and fake repositories backed by MutableStateFlow. Documented anti-patterns reject GlobalScope, init-block collection without scope, mutating lists inside MutableStateFlow, and creating flows in Composables without remember.
- Use viewModelScope or LaunchedEffect instead of GlobalScope for lifecycle-safe structured concurrency
- Parallelize repository calls with coroutineScope and async, then await results into one model
- Expose UI state via StateFlow.stateIn with WhileSubscribed to survive brief subscriber gaps
- Route one-time snackbars and navigation through SharedFlow effects collected in Compose
- Test StateFlow transitions with Turbine and runTest; fake repositories emit via MutableStateFlow
Kotlin Coroutines Flows by the numbers
- 5,944 all-time installs (skills.sh)
- +250 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #27 of 1,039 Mobile Development skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
kotlin-coroutines-flows capabilities & compatibility
- Capabilities
- use viewmodelscope or launchedeffect instead of · parallelize repository calls with coroutinescope · expose ui state via stateflow.statein with while · route one time snackbars and navigation through · test stateflow transitions with turbine and runt
- Use cases
- frontend · testing · api development
What kotlin-coroutines-flows says it does
常に構造化並行性を使用してください — `GlobalScope` は絶対に使わない
`WhileSubscribed(5_000)` は最後のサブスクライバーが離れてから 5 秒間アップストリームをアクティブに保ちます — 設定変更を再起動なしに生き延びます。
`CancellationException` をキャッチする — 適切なキャンセルのために伝播させる
npx skills add https://github.com/affaan-m/everything-claude-code --skill kotlin-coroutines-flowsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 5.9k |
|---|---|
| repo stars | ★ 238k |
| Security audit | 3 / 3 scanners passed |
| Last updated | August 5, 2026 |
| Repository | affaan-m/everything-claude-code ↗ |
What it does
Implement structured concurrency, Flow-based UI state, and coroutine tests in Android or KMP apps.
Who is it for?
Android or KMP developers writing ViewModel-driven UI, repository observation, debounced search, retrying network flows, or coroutine unit tests.
Skip if: Projects without Kotlin coroutines, pure synchronous scripts, or backends that never touch Android, Compose, or KMP client layers.
When should I use this skill?
Activate when writing Kotlin coroutine async code, using Flow or StateFlow for reactive data, handling parallel or debounced work, managing scopes and cancellation, or testing coroutines and flows.
What you get
Agents apply documented scope hierarchies, flow operators, dispatcher rules, and test harnesses so async Kotlin code stays lifecycle-safe, reactive, and verifiable.
- coroutine scope patterns
- flow pipelines
- coroutine tests
Files
Kotlin コルーチン & Flow
Android および Kotlin Multiplatform プロジェクトにおける構造化並行性、Flow ベースのリアクティブストリーム、コルーチンテストのパターン。
アクティベートするタイミング
- Kotlin コルーチンで非同期コードを書く
- リアクティブデータに Flow、StateFlow、または SharedFlow を使用する
- 並行操作を処理する(並列読み込み、デバウンス、リトライ)
- コルーチンと Flow をテストする
- コルーチンスコープとキャンセルを管理する
構造化並行性
スコープ階層
Application
└── viewModelScope (ViewModel)
└── coroutineScope { } (構造化された子)
├── async { } (並行タスク)
└── async { } (並行タスク)常に構造化並行性を使用してください — GlobalScope は絶対に使わない:
// NG
GlobalScope.launch { fetchData() }
// OK — ViewModel ライフサイクルにスコープ
viewModelScope.launch { fetchData() }
// OK — コンポーザブルライフサイクルにスコープ
LaunchedEffect(key) { fetchData() }並列分解
並列作業には coroutineScope + async を使用:
suspend fun loadDashboard(): Dashboard = coroutineScope {
val items = async { itemRepository.getRecent() }
val stats = async { statsRepository.getToday() }
val profile = async { userRepository.getCurrent() }
Dashboard(
items = items.await(),
stats = stats.await(),
profile = profile.await()
)
}SupervisorScope
子の失敗が兄弟をキャンセルしてはならない場合は supervisorScope を使用:
suspend fun syncAll() = supervisorScope {
launch { syncItems() } // ここでの失敗は syncStats をキャンセルしない
launch { syncStats() }
launch { syncSettings() }
}Flow パターン
コールドフロー — ワンショットからストリームへの変換
fun observeItems(): Flow<List<Item>> = flow {
// データベースが変更されるたびに再エミット
itemDao.observeAll()
.map { entities -> entities.map { it.toDomain() } }
.collect { emit(it) }
}UI 状態のための StateFlow
class DashboardViewModel(
observeProgress: ObserveUserProgressUseCase
) : ViewModel() {
val progress: StateFlow<UserProgress> = observeProgress()
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = UserProgress.EMPTY
)
}WhileSubscribed(5_000) は最後のサブスクライバーが離れてから 5 秒間アップストリームをアクティブに保ちます — 設定変更を再起動なしに生き延びます。
複数の Flow の結合
val uiState: StateFlow<HomeState> = combine(
itemRepository.observeItems(),
settingsRepository.observeTheme(),
userRepository.observeProfile()
) { items, theme, profile ->
HomeState(items = items, theme = theme, profile = profile)
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), HomeState())Flow オペレーター
// 検索入力のデバウンス
searchQuery
.debounce(300)
.distinctUntilChanged()
.flatMapLatest { query -> repository.search(query) }
.catch { emit(emptyList()) }
.collect { results -> _state.update { it.copy(results = results) } }
// 指数バックオフでリトライ
fun fetchWithRetry(): Flow<Data> = flow { emit(api.fetch()) }
.retryWhen { cause, attempt ->
if (cause is IOException && attempt < 3) {
delay(1000L * (1 shl attempt.toInt()))
true
} else {
false
}
}ワンタイムイベント用の SharedFlow
class ItemListViewModel : ViewModel() {
private val _effects = MutableSharedFlow<Effect>()
val effects: SharedFlow<Effect> = _effects.asSharedFlow()
sealed interface Effect {
data class ShowSnackbar(val message: String) : Effect
data class NavigateTo(val route: String) : Effect
}
private fun deleteItem(id: String) {
viewModelScope.launch {
repository.delete(id)
_effects.emit(Effect.ShowSnackbar("Item deleted"))
}
}
}
// コンポーザブルでコレクト
LaunchedEffect(Unit) {
viewModel.effects.collect { effect ->
when (effect) {
is Effect.ShowSnackbar -> snackbarHostState.showSnackbar(effect.message)
is Effect.NavigateTo -> navController.navigate(effect.route)
}
}
}ディスパッチャー
// CPU 集約型作業
withContext(Dispatchers.Default) { parseJson(largePayload) }
// IO バウンド作業
withContext(Dispatchers.IO) { database.query() }
// メインスレッド(UI)— viewModelScope ではデフォルト
withContext(Dispatchers.Main) { updateUi() }KMP では Dispatchers.Default と Dispatchers.Main(すべてのプラットフォームで利用可能)を使用してください。Dispatchers.IO は JVM/Android のみです — 他のプラットフォームでは Dispatchers.Default を使用するか DI で提供してください。
キャンセル
協調的キャンセル
長時間実行されるループはキャンセルを確認する必要があります:
suspend fun processItems(items: List<Item>) = coroutineScope {
for (item in items) {
ensureActive() // キャンセルされた場合は CancellationException をスロー
process(item)
}
}try/finally でのクリーンアップ
viewModelScope.launch {
try {
_state.update { it.copy(isLoading = true) }
val data = repository.fetch()
_state.update { it.copy(data = data) }
} finally {
_state.update { it.copy(isLoading = false) } // キャンセル時でも常に実行
}
}テスト
Turbine を使った StateFlow のテスト
@Test
fun `search updates item list`() = runTest {
val fakeRepository = FakeItemRepository().apply { emit(testItems) }
val viewModel = ItemListViewModel(GetItemsUseCase(fakeRepository))
viewModel.state.test {
assertEquals(ItemListState(), awaitItem()) // 初期値
viewModel.onSearch("query")
val loading = awaitItem()
assertTrue(loading.isLoading)
val loaded = awaitItem()
assertFalse(loaded.isLoading)
assertEquals(1, loaded.items.size)
}
}TestDispatcher でのテスト
@Test
fun `parallel load completes correctly`() = runTest {
val viewModel = DashboardViewModel(
itemRepo = FakeItemRepo(),
statsRepo = FakeStatsRepo()
)
viewModel.load()
advanceUntilIdle()
val state = viewModel.state.value
assertNotNull(state.items)
assertNotNull(state.stats)
}Flow のフェイク
class FakeItemRepository : ItemRepository {
private val _items = MutableStateFlow<List<Item>>(emptyList())
override fun observeItems(): Flow<List<Item>> = _items
fun emit(items: List<Item>) { _items.value = items }
override suspend fun getItemsByCategory(category: String): Result<List<Item>> {
return Result.success(_items.value.filter { it.category == category })
}
}避けるべきアンチパターン
GlobalScopeの使用 — コルーチンがリークし、構造化キャンセルがない- スコープなしで
init {}内で Flow をコレクトする —viewModelScope.launchを使用 - ミュータブルコレクションで
MutableStateFlowを使用する — 常にイミュータブルコピーを使用:_state.update { it.copy(list = it.list + newItem) } CancellationExceptionをキャッチする — 適切なキャンセルのために伝播させる- コレクトするために
flowOn(Dispatchers.Main)を使用する — コレクションディスパッチャーは呼び出し元のディスパッチャー rememberなしで@Composable内にFlowを作成する — 再コンポジションのたびにフローが再作成される
参考
スキル: compose-multiplatform-patterns で Flow の UI 消費を参照。 スキル: android-clean-architecture でレイヤーにおけるコルーチンの役割を参照。
Related skills
Forks & variants (1)
Kotlin Coroutines Flows has 1 known copy in the catalog totaling 1.4k installs. They canonicalize to this original listing.
- affaan-m - 1.4k installs
FAQ
When should I use supervisorScope instead of coroutineScope?
Use supervisorScope when a failure in one child must not cancel sibling coroutines, such as independent sync tasks that should continue after one branch errors.
How should one-time UI events differ from StateFlow state?
Model persistent UI state in StateFlow, but emit snackbars and navigation through a SharedFlow effects channel collected once in Compose via LaunchedEffect.
What coroutine testing tools does the skill recommend?
Use Turbine to assert StateFlow emissions in order, runTest with advanceUntilIdle for parallel loads, and fake repositories that expose MutableStateFlow-backed flows.
Is Kotlin Coroutines Flows safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.