Workshop: Jetpack Compose #
In this workshop, we will introduce the Jetpack Compose framework used for building Android apps. The demo we will be following is a minimal online Notes app. You can clone this code, follow the steps to setup Firebase, then you should be able to run the app yourself as well.
This document will explain several key concepts and steps:
- How to create UI with Jetpack Compose, following the MVVM architecture;
- How to connect with Firebase, which provides various of backend services including authentication and database.
Jetpack Compose #
UI (Composable) #
In Jetpack Compose, each UI element is called a composable, and creating UI is essentially a top-down process of writing composables that contains smaller composables.
- Screen is usually the top-most composable, essentially representing what user sees on the entire phone screen.
- In the middle level, container-like composables like
Box,Column, andRowwill help you organize the UI layout. - The built-in composables, following the Material Design, are the smaller composables you can select from.
For example, this is a excerpt from the NoteScreen showing how composable works:
@Composable
fun NoteScreen(.., viewModel: NoteViewModel) {
..
Column(modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()) {
TopAppBar(
title = {
Text(text = note.value.getTitle(),)
},
actions = {
IconButton(onClick = { viewModel.saveNote(popUpScreen) }) {
Icon(Icons.Filled.Done, "Save note")
}
IconButton(onClick = { viewModel.deleteNote(popUpScreen) }) {
Icon(Icons.Filled.Delete, "Delete note")
}
}
)
Spacer()
Column(..) {
TextField(
value = note.value.text,
onValueChange = { viewModel.updateNote(it) },
..
)
}
}
}
Which essentially creates a screen like this:

MVVM #
The MVVM (Model-View-ViewModel) architecture is an architectural style used in the presentation+domain layers of modern apps with UI. A detailed introduction to MVVM is available in a separate document: MVVM (MVC, MVP).
A typical way of organizing code, in this demo, is:
screens/ # View and ViewModel
account_center/ # .. a pair of View and ViewModel for a screen
AccountCenterScreen.kt
AccountCenterViewModel.kt
authentication/
sign_in/
SignInScreen.kt
SignInViewModel.kt
sign_up/
SignUpScreen.kt
SignUpViewModel.kt
CredentialsExt.kt # .. utility composables/functions
ValidationsExt.kt # shared by multiple screens
note/
NoteScreen.kt
NoteViewModel.kt
notes_list/
NotesListScreen.kt
NotesListViewModel.kt
splash/
SplashScreen.kt
SplashViewModel.kt
model/ # Model
Note.kt # .. data classes
User.kt
service/ # .. interface
AccountService.kt
StorageService.kt
impl/ # .. implementation
AccountServiceImpl.kt
StorageServiceImpl.kt
Authentication with Firebase #
We use Firebase Authentication to handle user sign-in, which also supports many third-party OAuth providers such as Google Sign-In.
Logic Flow #
Below is the sequence diagram for the regular sign-in with email and password flow:

For comparison, here is the sequence diagram for the Google Sign-In flow:

Setup Firebase #
Official Documentation: Authenticate with Google on Android
Create a project in the Firebase Console.
Go to Settings > General > Your apps, add your Android app; follow the steps to update build configurations.

- Go to Authentication (if first time, click “Get Started” to enable this service), enable “Email/Password”, “Anonymous”, and “Google” providers.

- For Signin with Google to work, your app needs a signing certificate SHA-1. You can get a debug SHA-1 now by running
./gradlew signingReport(see screenshot below), but later when you release the app on Play Store, switch to Play App Signing.

- Go back to Firebase Console, Settings > General > Your apps, “Add fingerprint” to add the signing certificate; then don’t forget to download the updated
google-services.jsonfile and place it in theapp/directory of your project.

- Go to Firestore (if first time, click “Get Started” to enable this service), add a collection called “notes”.

- Switch to the “Rules” tab, and insert the following rules (before the default denying all rule
match /{document=**} { allow read, write: if false; }):
match /notes/{note} {
// Users can only read, update, and delete their own notes
allow read, update, delete: if request.auth.uid == resource.data.userId;
// Users can only create notes for themselves
allow create: if request.auth.uid == request.resource.data.userId;
}

Misc Technical Notes #
Build Configuration #
A couple of new dependencies and plugins need to be added (Jetpack Compose, Firebase, Hilt) compared to the project template created by Android Studio. Check the app-level build.gradle.kts for details, where I’ve tried to group the added dependencies/plugins by framework. Note that Firebase’s dependencies versions are managed via BoM.
Resources #
The text used in buttons/labels are added in strings.xml. They can be used in code like R.string.XXX.
There are also two image resources added: google_g.xml and auth_image.png.
Manifest Configuration #
In the manifest file, you need to add android:name=".NotesHiltApp" into the application field for Hilt to work.
Further Reading #
Other technologies used in the demo:
- Navigation to jump between screens, maintaining a stack to support back navigation.
- Dependency Injection with Hilt