Architecture

Unidirectional Data Flow

By passing data into functions, and receiving event calls out, we remove the possibility of data changing while it's being read.

Jetpack Compose's Composable functions take parameters for data and events. For example, we might define a "submit button" function:

@Composable
fun Submit(
    buttonText: String,
    onButtonPress: () -> Unit,
) {
    ...
}

Note

The convention for Composable functions that emit ui nodes to the tree is that they are named using UpperCamelCase(). This feels a bit weird, but the idea is that we're treating these functions as declarations of what the ui looks like, not imperative code to build a UI. Declarations feel more like class or interface definitions, hence the case.

The buttonText is data coming in; the Submit() function will emit a button to the tree that displays that text. Submit() will also attach a "click listener" to the button. When the button is pressed, it will call onButtonPress() to tell the caller of Submit() that the button was pressed.

Data comes in; events go out. That's Unidirectional Data Flow.

Somewhere up at the top of the call chain, a lambda is passed in to be used as that onButtonPress parameter, and it contains the code to perform the update.

That lambda should immediately switch to a different thread to perform its work. We'll do this by launching a coroutine to perform the work. At the end of the coroutine, new data will be set for the state and passed in.

For this example, if the new state contains the buttonText that's passed into SubmitButton(), the UI will be updated.

We'll dig into this when we start talking about Jetpack Compose. For now, all you need to know is we'll be pushing data and event functions into the Composable functions, and call the event functions to indicate that something has changed.