みんなはいくつ使っていますか。

🧑🏻💻 1. stateIn: Flow を StateFlow に変換する
宣言的な uiState の締めくくりです。WhileSubscribed(5_000) にしておくと、画面回転では再購読せず、バックグラウンドでは上流を止められます。
val uiState: StateFlow<UiState> = flow
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = UiState.Loading
)
🧑🏻💻 2. combine: 複数ソースを 1 つの UiState に合成する
MutableStateFlow を何本も手で更新する代わりに、「ソースの合成結果 = UiState」と宣言できます。
combine(repo.items, query, filter) { items, q, f ->
UiState.Success(items.filter { it.matches(q, f) })
}
🧑🏻💻 3. map: ドメインモデルから UI モデルへの変換
整形や表示用の変換はここに集約します。
repo.user.map { it.toUiModel() }
🧑🏻💻 4. flatMapLatest: 入力の変化で上流を切り替える
検索クエリや選択 ID が変わると、前のリクエストを自動キャンセルして新しい Flow に切り替えます。
query.flatMapLatest { q -> repo.search(q) }
🧑🏻💻 5. catch: エラーを UiState に変換する
例外を UI の状態として扱えます。上流のエラーだけを捕捉する点が try/catch との違いです。
.catch { emit(UiState.Error(it.message)) }
🧑🏻💻 6. onStart: Loading の初期値を流す
購読開始時に Loading を流す定番の書き方です。
repo.items
.map<_, UiState> { UiState.Success(it) }
.onStart { emit(UiState.Loading) }
🧑🏻💻 7. distinctUntilChanged: 無駄な再描画を防ぐ
StateFlow 自体も同値を弾きますが、中間の Flow で重い処理の前に挟むと効果的です。
query.distinctUntilChanged()
.flatMapLatest { repo.search(it) }
🧑🏻💻 8. debounce: 入力の連打を間引く
検索ボックスなどで使います。debounce は同値の弾き込みはしないため、distinctUntilChanged と併用します。
query.debounce(300)
.distinctUntilChanged()
🧑🏻💻 9. scan / runningFold: 状態を畳み込む
ページング風の追加読み込みや、イベントから状態を積み上げる MVI 的な設計で使います。
events.scan(UiState()) { state, event -> reduce(state, event) }
🧑🏻💻 10. flowOn: 上流の実行スレッドを指定する
重い変換や IO を Main から外します。上流にだけ効く点に注意してください。
repo.items
.map { heavyTransform(it) }
.flowOn(Dispatchers.Default)
🧑🏻💻 よくある組み合わせ例
class SearchViewModel(repo: SearchRepository) : ViewModel() {
private val query = MutableStateFlow("")
private val filter = MutableStateFlow(Filter.All)
val uiState: StateFlow<UiState> = combine(
query.debounce(300).distinctUntilChanged()
.flatMapLatest { repo.search(it) },
filter
) { results, f ->
UiState.Success(results.filter(f::accepts)) as UiState
}
.onStart {
emit(UiState.Loading)
}
.catch {
emit(UiState.Error(it.message))
}
.flowOn(Dispatchers.Default)
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000),
UiState.Loading
)
fun onQueryChange(q: String) {
query.value = q
}
}
🧑🏻💻 参考
Related Categories : Android・Developmemt・GitHub・JetpackCompose・KMP・Kotlin・Kotlin Multiplatform Mobile・Newbie・Recommended・Trending