
Lightweight coroutine-based unidirectional data-flow architecture for predictable state management, mapping events→actions→results→state, with interactor pipelines, side-effect handling, lifecycle-scope integration and UI screen binding.
This repository provides a library implementing a lightweight, coroutine-based Unidirectional Data Flow (UDF) architecture for Kotlin applications, with a focus on Android and Jetpack Compose.
The UDF pattern establishes a single, directional flow of data through your application, making state management predictable and easier to debug.
Event → Action → Result → State
↓
Effect (side effects)
This project is organized into several modules:
arch: Kotlin Multiplatform UDF core (Feature, StandardFeature, Interactor). Supports Android, iOS (iosArm64, iosSimulatorArm64). See the arch module README.arch-android: Android-specific ViewModel integration (ViewModelFeature). See the arch-android module README.ui: Jetpack Compose screen binding helpers (Screen, StandardScreen). See the ui module README.compose: Sample Android application demonstrating the library.Artifacts are published to Maven Central (mavenCentral() is already included by default in most modern Android and KMP projects).
// build.gradle.kts
dependencies {
// Platform-agnostic UDF core (Kotlin Multiplatform)
implementation("io.github.reid-mcpherson:arch:1.0.2")
// Android ViewModel integration (includes :arch transitively)
implementation("io.github.reid-mcpherson:arch-android:1.0.2")
}Add :arch to your shared commonMain source set. Gradle resolves
the correct platform variant (Android, iOS, etc.) automatically.
// build.gradle.kts (KMP module)
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.reid-mcpherson:arch:1.0.2")
}
}
}Supported targets: Android, iOS (iosArm64, iosSimulatorArm64)
:arch-androidis Android-only and wraps:archwithViewModelandviewModelScope. Use it in your Android-specific source set.
Feature (com.composure.arch): The main interface for interacting with a UDF component, providing a StateFlow of the current state and a Flow of side effects.StandardFeature (com.composure.arch): A platform-agnostic base class for creating UDF features in any Kotlin application.ViewModelFeature (com.composure.arch): An Android-specific implementation that integrates with ViewModel and viewModelScope.StandardScreen (com.composure.ui): An abstract Compose screen base class that wires a ViewModelFeature to a composable UI.The pattern uses five main types to model the data flow:
| Type | Purpose | Example |
|---|---|---|
STATE |
Represents the current UI state | data class UiState(val users: List<User>, val loading: Boolean) |
EVENT |
User interactions or system events | sealed class Event { object LoadUsers : Event() } |
ACTION |
Business logic intents derived from events | sealed class Action { object FetchUsers : Action() } |
RESULT |
Outcomes of processing actions | sealed class Result { data class UsersLoaded(val users: List<User>) : Result() } |
EFFECT |
One-time side effects (e.g., navigation, toasts) | sealed class Effect { object NavigateHome : Effect() } |
class MyViewModel : ViewModelFeature<State, Event, Action, Result, Effect>() {
override val initial = State.Initial
override val eventToAction: Interactor<Event, Action> = { events ->
events.map { event ->
when (event) {
Event.LoadUsers -> Action.FetchUsers
}
}
}
override val actionToResult: Interactor<Action, Result> = { actions ->
actions.flatMapMerge { action ->
when (action) {
Action.FetchUsers -> flow {
emit(Result.Loading)
emit(Result.UsersLoaded(repository.getUsers()))
}
}
}
}
override suspend fun handleResult(previous: State, result: Result): State {
return when (result) {
is Result.Loading -> previous.copy(isLoading = true)
is Result.UsersLoaded -> previous.copy(isLoading = false, users = result.users)
}
}
}This repository provides a library implementing a lightweight, coroutine-based Unidirectional Data Flow (UDF) architecture for Kotlin applications, with a focus on Android and Jetpack Compose.
The UDF pattern establishes a single, directional flow of data through your application, making state management predictable and easier to debug.
Event → Action → Result → State
↓
Effect (side effects)
This project is organized into several modules:
arch: Kotlin Multiplatform UDF core (Feature, StandardFeature, Interactor). Supports Android, iOS (iosArm64, iosSimulatorArm64). See the arch module README.arch-android: Android-specific ViewModel integration (ViewModelFeature). See the arch-android module README.ui: Jetpack Compose screen binding helpers (Screen, StandardScreen). See the ui module README.compose: Sample Android application demonstrating the library.Artifacts are published to Maven Central (mavenCentral() is already included by default in most modern Android and KMP projects).
// build.gradle.kts
dependencies {
// Platform-agnostic UDF core (Kotlin Multiplatform)
implementation("io.github.reid-mcpherson:arch:1.0.2")
// Android ViewModel integration (includes :arch transitively)
implementation("io.github.reid-mcpherson:arch-android:1.0.2")
}Add :arch to your shared commonMain source set. Gradle resolves
the correct platform variant (Android, iOS, etc.) automatically.
// build.gradle.kts (KMP module)
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.reid-mcpherson:arch:1.0.2")
}
}
}Supported targets: Android, iOS (iosArm64, iosSimulatorArm64)
:arch-androidis Android-only and wraps:archwithViewModelandviewModelScope. Use it in your Android-specific source set.
Feature (com.composure.arch): The main interface for interacting with a UDF component, providing a StateFlow of the current state and a Flow of side effects.StandardFeature (com.composure.arch): A platform-agnostic base class for creating UDF features in any Kotlin application.ViewModelFeature (com.composure.arch): An Android-specific implementation that integrates with ViewModel and viewModelScope.StandardScreen (com.composure.ui): An abstract Compose screen base class that wires a ViewModelFeature to a composable UI.The pattern uses five main types to model the data flow:
| Type | Purpose | Example |
|---|---|---|
STATE |
Represents the current UI state | data class UiState(val users: List<User>, val loading: Boolean) |
EVENT |
User interactions or system events | sealed class Event { object LoadUsers : Event() } |
ACTION |
Business logic intents derived from events | sealed class Action { object FetchUsers : Action() } |
RESULT |
Outcomes of processing actions | sealed class Result { data class UsersLoaded(val users: List<User>) : Result() } |
EFFECT |
One-time side effects (e.g., navigation, toasts) | sealed class Effect { object NavigateHome : Effect() } |
class MyViewModel : ViewModelFeature<State, Event, Action, Result, Effect>() {
override val initial = State.Initial
override val eventToAction: Interactor<Event, Action> = { events ->
events.map { event ->
when (event) {
Event.LoadUsers -> Action.FetchUsers
}
}
}
override val actionToResult: Interactor<Action, Result> = { actions ->
actions.flatMapMerge { action ->
when (action) {
Action.FetchUsers -> flow {
emit(Result.Loading)
emit(Result.UsersLoaded(repository.getUsers()))
}
}
}
}
override suspend fun handleResult(previous: State, result: Result): State {
return when (result) {
is Result.Loading -> previous.copy(isLoading = true)
is Result.UsersLoaded -> previous.copy(isLoading = false, users = result.users)
}
}
}