A Short Intro to Thinking in Jetpack Compose
Tags: android, compose
Published: 2023-01-16 18:50:14

> **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](https://developer.android.com/jetpack/compose/interop/adding).

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.

```csharp
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.

```kotlin
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.

```java
    +---------------+
    |      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.

```Kotlin
@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 the `showDialog` to `false` 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.