The Struggling Dev
Posted on January 16, 2023
Disclaimer
This is not an in-depth tutorial for Compose. I won't go over what dependencies you need to add, ... - you can find that here Android Developers - Adding Jetpack Compose to your app.
This post is a short introduction to Jetpack Compose, mainly about what makes it different from other UI frameworks.
As you might've guessed, Jetpack Compose is a UI framework. What makes it different from more common UI frameworks like WinForms, WPF, Swing, Tkinter, ... is that it is a declarative UI framework. What does that mean? In short: You declare a UI and that's it, you're out of the picture. You can't programmatically "interact" with the UI components as you would in a non-declarative framework.
For example if you wanted to change the text of a text view in response to a button click, you'd do something like this in a non-declarative UI framework.
StackPanel stackPanel = new StackPanel();
TextBox textBox = new TextBox();
stackPanel.Children.Add(textBox)
Button button = new Button();
stackPanel.Children.Add(button);
button.Click += (sender, ea) => { textBox.Text = "Button Pressed"; }
Here we create the UI and directly interact with other UI elements, we can change their properties. This doesn't work in Compose. Although you can keep references to Composables (≈ UI components), you can't change their properties.
val textComposable = Text(text = "Hello Compose.")
textComposable.text = "This won't compile, because there's no text property."
Compose is designed around the Unidirectional Data Flow (UDF) pattern. The UI triggers events that allow you to change state, which in turn triggers the recomposition (~ rebuilding/drawing the UI) of the UI.
+---------------+
| UI |
+---------------+
| ^
event | | state
v |
+---------------+
| State |
+---------------+
Having used only non-declarative UI frameworks, the use case that helped me most in understanding how to think in Compose was showing a dialog. The following composable function does exactly this.
@Composable
fun SampleScreen() {
val showDialog = remember { mutableStateOf(false) } // changes to states trigger recomposition
TextButton(onClick = { showDialog.value = true }) {
Text(text = "Click to show the dialog")
}
if (showDialog.value) {
Dialog(onDismissRequest = { showDialog.value = false }) {
Text(text = "Tap outside the dialog to close it.")
}
}
}
What's happening here? When the Composable is executed for the first time the showDialog
variable is set to false
and we therefore don't add the dialog to our GUI. If we click on the button and set the value of showDialog
to true
, we trigger a re-composition of the Composable (b/c showDialog
is a mutable state). The Composable is 're-executed', this time around showDialog
is true
and we show our dialog.
Remember Me
remember
allows a composable function to store information in memory so that that information is still available after recomposition.
- If we would just write
val showDialog = mutableStateOf(false)
, the UI would be recomposed, but we would re-initialize theshowDialog
tofalse
and therefore not show the dialog.- And
var showDialog = false
wouldn't even trigger recomposition, therefore no dialog either.Instead of
remember
we can also use a view model.
That's it for this short introduction to thinking in Compose.
Keep on struggling.
Posted on January 16, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.