Architecture Overview Unidirectional Data Flow ● Higher layers react to changes in lower layers. ● Events flow down. ● Data flows up with data streams. (Kotlin Flows) Unidirectional Event Flow
Architecture - UI Layer Modeling UI state ● UI state always represents the underlying app data. ● UI elements handle all possible states. Transforming streams into UI state ● View models receive streams of data as Flows from data layers. ● The single flow is converted to StateFlows, which enables UI elements to read the last state. Processing user interactions (Unidirectional event flow) ● User actions are communicated from UI elements to view models. ● View models execute business logic following the user interactions.
A single source of truth principle is a philosophy of aggregating the data from many systems within an organization to a single location. Architecture - Data Layer
interface Syncable { /** * Synchronizes the local database backing the repository with the network. * Returns if the sync was successful or not. */ suspend fun syncWith(synchronizer: Synchronizer): Boolean } Architecture - Sync
interface Syncable { /** * Synchronizes the local database backing the repository with the network. * Returns if the sync was successful or not. */ suspend fun syncWith(synchronizer: Synchronizer): Boolean } Architecture - Sync interface TopicsRepository : Syncable class OfflineFirstTopicsRepository @Inject constructor( .. ) : TopicsRepository { override suspend fun syncWith(synchronizer: Synchronizer): Boolean = synchronizer.changeListSync( ..
interface Syncable { /** * Synchronizes the local database backing the repository with the network. * Returns if the sync was successful or not. */ suspend fun syncWith(synchronizer: Synchronizer): Boolean } Architecture - Sync interface TopicsRepository : Syncable class OfflineFirstTopicsRepository @Inject constructor( .. ) : TopicsRepository { override suspend fun syncWith(synchronizer: Synchronizer): Boolean = synchronizer.changeListSync( .. Versioning each model
class SyncInitializer : Initializer { override fun create(context: Context): Sync { WorkManager.getInstance(context).apply { // Run sync on app startup and ensure only one sync worker runs at any time enqueueUniqueWork( SyncWorkName, ExistingWorkPolicy.REPLACE, SyncWorker.startUpSyncWork() ) } return Sync } override fun dependencies(): List>> = .. } Architecture - Sync Returns OneTimeWorkRequest
Architecture - ForYou Screen The recommendations and best practices present in this architecture can be applied to a broad spectrum of apps to allow them to scale, improve quality and robustness, and make them easier to test. However, you should treat them as guidelines and adapt them to your requirements as needed.
Composable functions can use the remember API to store an object in memory. A value computed by remember is stored in the Composition during initial composition, and the stored value is returned during recomposition. UI Layer - Remember