BlogDecember 20, 2019
Jetpack Compose: A Declarative Android UI Toolkit
At Google I/O 2019, Google announced the new Jetpack Compose library for Android UI development. Updates on the development of Compose were also shared at the Android Dev Summit. Although Google strongly cautions that Jetpack Compose is not ready for use in production, the first developer preview of Compose was released in the latest version of Android Studio Preview.
What is Jetpack Compose?
Jetpack Compose is a library that is being developed by Google in order to create a more modern and versatile framework for Android UI development. The existing View-based UI framework is as old as Android itself and thus it has many features within it that were created for old devices and based on old methodologies.
Inspired by recent web languages such as Flutter, React, Litho, and Vue.js, Compose allows developers to create UI components in a declarative manner (Apple announced a declarative UI library of its own, Swift UI for iOS, at WWDC this year).
These are some of the advantages Compose will bring to Android UI development:
Independence from Android platform releases
The Compose framework is integrated into applications as a Jetpack library, meaning that it is unbundled from Android platform releases. This allows Compose to be updated more frequently than the existing View-based UI framework.
This unbundled approach also means that Jetpack Compose is backward compatible with older versions of Android, so it can be added to existing applications that are already using the View-based UI framework.
Simplified UI code
Creating layouts with the current Android UI paradigm often requires writing a fairly significant amount of code, especially for more complex UI elements.
Additionally, UI code that uses the current Android UI framework is usually spread across several different places within a codebase, which can complicate and slow down UI development. Spreading code related to the UI is often thought of as adhering to the “separation of concerns” principle of software design. However, Leland Richardson of the Android team explained at the Android Dev Summit and on the Fragmented Podcast why this separation is not always ideal.
Compose aims to simplify the UI development process by allowing developers to write less code in fewer places within a codebase.
Rather than using separate XML files for each layout within an application, Compose is written in Kotlin. This allows a developer to use the features that Kotlin provides (e.g. for loops, if statements, lambda expressions, etc.) when creating UI widgets. It also opens the door for better debugging and testing of UI widgets.
UI components built with Compose are built with Composable functions that “are defined in terms of other Composable functions.” This means that each UI component created with Compose is reusable, which helps prevent the urge to have various similar copies of layouts within a codebase.
Each Composable function can either call another Composable function or emit part of the UI tree. Whenever the state of a Composable widget changes, only the part of the UI tree that has been updated will be recomposed.
A single source of truth
In Compose, data always flows downward from the app’s data model to Composable UI widgets. In turn, events that occur on UI widgets are passed back up to the data model. This simplified data flow allows the app’s data model to be the single source of truth for the UI. This chart from the Jetpack Compose Google Codelab visualizes this data flow pattern:
At a high-level, the Jetpack Compose library can be thought of as being made up of two parts:
- the Compose declarative UI toolkit that allows developers to define UI widgets as Composable functions (identified with the @Composable annotation)
- the Compose compiler plugin
Let’s take a look at some code to get a better feel for what Jetpack Compose offers.
This function displays some simple text on a screen using a Text widget:
We can set the ComposeScreen() widget to display as the top-level UI widget for an Activity using setContent (similar to the current method setContentView):
Padding can be added around the Text widget by wrapping it with a Padding widget:
Now, suppose we want to display a static list of items on the screen:
We can use the Column widget (similar to the current LinearLayout), and then use the Kotlin forEach lambda function to display each item in the list within a Row widget:
What if we have some dynamic data that we wish to display on a screen? The @Model annotation can be used to create data model objects. These data model objects are “observable” and @Composable widgets will recompose themselves when any data model object changes.
Consider the simple example data model ScreenModel below that has a boolean variable that is toggled when the user clicks a button:
We can see that the Button’s onClick handler triggers the changeColor() function callback in the data model. When the buttonColorToggle variable changes, the ColorButton widget is automatically recomposed to update the color of the button on the screen.
A few additional widgets were also used in the above example:
- the MaterialTheme widget wrapped around the ColorButton provides styling for widgets such as the Button widget
- the Center widget is used to align the Button in the center of the screen
- the ContainedButtonStyle widget passes styling properties such as color and shape to the Button
The code samples above provide a brief glimpse into how Compose looks and behaves.
The Jetpack Compose library is an exciting idea that has the potential to re-shape Android UI development. Given that redesigning the Android UI system is a very large task, Compose will surely continue to undergo changes before it is ready to be used in production. It will be fun to watch the evolution of this promising framework!
If you would like to take a deeper look into the Compose library, the open-source code is currently available here in AOSP. This guide from Google describes how to use Compose with the latest version of Android Studio Preview.
Graham Parvinkarimi is a Senior Software Engineer at CapTech, based in Washington, DC. He has experience building mobile and web applications for companies in a variety of industries.