June 20, 2023
Architecture in Jetpack Compose and Gets Some information in Unidirectional Data Flow in Jetpack Compose
An Architecture component is a software unit that encapsulates well defined functionality into a binary unit that can be stored in a library and dropped into an application without requiring modification of other components.
Architecture components are the building blocks of Service-Oriented and Microservice architectures, in which applications are assembled from loosely coupled and discrete services.
Benefits of Architecture Component
- Reduced Development Time.
- Reduced Testing Time.
- Enhanced reliability.
Types of Architecture Component
- A module is a self-contained unit of code that provides a specific function. Modules are typically compiled into a single binary file, which makes them easy to reuse.
- A service is a component that provides a specific function over a network. Services are typically implemented using web services or RPC protocols.
- A framework is a collection of pre-written code that provides a common foundation for building software applications. Frameworks can be used to speed up development and improve the quality of software.
Android Architecture Components
Architecture Components are a set of libraries that provide a foundation for building robust, high-quality Android apps.
The Architecture Components are a valuable tool for building Android apps. They can help to improve the quality, maintainability, and scalability of apps.
Patterns in Android
Patterns in Android are design patterns that are commonly used in Android development. They provide a way to solve common problems in a consistent and efficient way.
MVP — Model View Presenter
- In the context of Android app development with Jetpack Compose, MVP stands for Model-View-Presenter. However, Jetpack Compose follows a different architectural pattern called the “unidirectional data flow” or “state hoisting” pattern. This pattern is recommended for building apps with Jetpack Compose as it simplifies the architecture and takes advantage of the declarative nature of Compose
MVI — Model View Intent
- Model-View-Intent (MVI) pattern is not specifically tied to Jetpack Compose, you can still implement it with Jetpack Compose to manage the state and user interactions in a reactive and predictable way. The MVI Pattern emphasizes unidirectional data flow and immutability of the State
MVVM — Model View ViewModel
- In Jetpack Compose, the recommended architectural pattern is the Mode-View-ViewModel (MVVM) Pattern. MVVM is well-suited for Jetpack Compose because it leverages the reactive and declarative nature of Compose.
Basically In Jetpack Compose is Architecting Unidirectional Data Flow Pattern, It’s in MVP and MVI
Architecting your Jetpack Compose UI
Jetpack Compose UI is Immutable, There’s no way to update it after it’s been drawn . What you can control is the state of your UI. Every time the State of the UI changes, Compose recreates the parts of the UI tree that have changed. Composables can accept state and expose events, The Unidirectional data flow pattern fits well with Jetpack Compose.
Unidirectional Data Flow(UDF)
A Unidirectional data flow(UDF) is a design pattern where state flows down and events flow up. By following Unidirectional Data Flow, you can decouple composables that display state in the UI from the parts of your App that store and change state.
The UI update loop for an app using unidirectional data flow looks like this:
- Part of the UI generates an event and passes it upward, such as a button click passed to the ViewModel to handle; or an event is passed from other layers of your app, such as indicating that the user session has expired.
- An event handler might change the state.
- The state holder passes down the state, and the UI displays it.
The Pattern is in Jetpack Compose Provides Several Advantages:
- Decoupling state from the UI that displays it makes it easier to test both in isolation.
- Because state can only be updated in one place and there is only one source of truth for the state of a composable state, it’s less likely that you’ll create bugs due to inconsistent states.
- All state updates are immediately reflected in the UI by the use of observable state holders
Events in Jetpack Compose
Every input to your app should be represented as an event: taps, text changes, and even timers or other updates. As these events change the state of your UI, the ViewModel should be the one to handle them and update the UI state.
The UI layer should never change state outside of an event handler because this can introduce inconsistencies and bugs in your application.
Prefer passing immutable values for state and event handler lambdas.
- You improve reusability.
- You ensure that your UI doesn’t change the value of the state directly.
- You avoid concurrency issues because you make sure that the state isn’t mutated from another thread.
- Often, you reduce code complexity.
Example: ViewModels, States, and Events
By using ViewModel and mutableStateOf, you can also introduce unidirectional data flow in your app if one of the following is true:
- The state of your UI is exposed via observable state holders, like StateFlow or LiveData.
- The ViewModel handles events coming from the UI or other layers of your app and updates the state holder based on the events.
For example, when implementing a sign-in screen, tapping on a Sign in button should cause your app to display a progress spinner and a network call. If the login was successful, then your app navigates to a different screen; in case of an error the app shows a Snackbar. Here’s how you would model the screen state and the event:
The screen has four states:
- Signed out: when the user hasn’t signed in yet.
- In progress: when your app is currently trying to sign the user in by performing a network call.
- Error: when an error occurred while signing in.
- Signed in: when the user is signed in.
You can model these states as a sealed class. The ViewModel exposes the state as a State, sets the initial state, and updates the state as needed. The ViewModel also handles the sign-in event by exposing an onSignIn() method.
In this document, we have presented an Android architecture that is designed to be maintainable, scalable, and secure. We have discussed the key architectural decisions we made, and we have summarized the benefits of our architecture. We have also challenged the reader to think about the future of their app and how their architecture might need to change as their app grows and evolves.
We believe that this architecture is a good starting point for building Android apps. However, we also believe that it is important to be flexible and adaptable. As your app grows and evolves, you may need to make changes to your architecture. We encourage you to experiment and find what works best for your app.
Thank you for reading this document. We hope that you found it helpful.