This sample demonstrates how to use some of the Android Architecture Components available in Jetpack library.
I tried to follow the principles of Clean Architecture and use some cool Android libraries. The UI is implemented using Jetpack Compose and MVVM pattern. Application data can be persisted either locally into device (using SQLite) or remotely (using Firebase).
The Application is splitted in modules as explained below:
- app - it's the application start point and it has access to all other project's modules.
Therefore Hilt modules
are defined to inject the required dependencies to the application classes.
The navigation logic is implemented using Jetpack Navigation for Compose in order to follow the "single-activity" approach, thus to navigate between application's features, the main navigator is defined here and used by theMainActivity
. The navigation between the screens in a module is implemented in each module. - core - is a pure Kotlin module and contains core classes used across the whole app
like:
ResultState
which represent a result for a request to a repository;AppRoutes
which is a generic definition of a route to a screen; etc. - core_android - contains core resources, components and classes which depend on Android framework and/or libraries. For instance: reusable Compose components; styles and themes; file system related classes.
- data_firebase - this module has an implementation of a remote data source using Firebase Cloud Firestore and in order to store book's covers, Firebase Cloud Storage is used.
- data_local - defines an implementation of a local data source using Room library. The book's cover are stored in the local file system.
- domain - this module is where the application's use cases are declared. The interfaces for
repositories are also declared here, but the implementation itself is in data_local and/or *
data_firebase* modules. Finally, here is where the navigation abstraction is defined via
Router
interface. - feature/login - under "features" folder are defined all application's features. Login feature
is where authentication process is implemented
using Firebase Authentication. The UI for the login is
also defined here.
- feature/books - this is the main application module, where the books are created, read,
updated and deleted. Since this project is following (or trying to)
the MVVM pattern, this
module is using View Model
library to keep data across config changes.
To expose observable data from the View Models, this module is usingStateFlow
which are observed by the screens. - feature/settings - this module define a simple application settings which allows the user to set the application's theme (light mode, dark mode or follow system preferences)
The architecture data flow is displayed below:
Basically, the repository is responsible to save and restore data. This data are provided
via Flow
.
A use case is responsible to perform business validations and acts like a reusable bridge between
view models and repositories. View models will keep the UI state and expose this state to the
screens (via StateFlow
). When a user do some action, the view model handles this action and change
its internal state, since the screen is observing this state, it should react accordingly.
Finally, screens are composable components which send actions to the view model and observe the
changes on their state.
This screen displays all books saved on the repository (local or remote).
This screen display the details of a book selected in books list.
In this screen, the user can add a new book or edit an existing one.
The user must perform the login with their Google account to access the application.
This project is written in Kotlin and it's using the following libraries:
- Jetpack Compose core libraries;
- Material Design libraries;
- Jetpack Libraries (KTX, Exif, Hilt, Navigation, View Model and Room);
- Compose Accompanist Libraries (Navigation and Swipe to Refresh)
- Firebase Libraries for Android (Authentication, Firestore and Storage);
- Coil Image for image loading;
- Reveal Swipe;
- Coroutines
- JUnit
- MockK
The project is compatible with Android Studio Dolphin | 2021.3.1 Canary 3. To run this application,
you must have to create a Firebase Project
and enable Google Authentication.
Afterwards, you must have to download the google_services.json
file from the firebase console and
add it to app
module root folder. If you want to save data on Firebase Cloud
Firestore, enable a database for your
project in Firebase Console.
Also enable the Firebase Cloud Storage to
store the books cover images.
To choose the data source you will save application data, just make the following change in the RepositoryModule.kt file.
@Provides
fun providesBookRepository(
@ApplicationContext context: Context
): BooksRepository {
// For local repository use this line
return RoomLocalRepository(context, LocalFileHelper())
// For firebase repository use this line
return FirebaseBookRepository()
}
And that's it! You're good to go.
./gradlew clean
./gradlew test connectedAndroidTest
./gradlew dependencyUpdates
This project is just a sample, but any feedback and/or PR's are really appreciated! :)