Philosophies of State

Let’s start by discussing how framework views approach state. The apps you worked on earlier in this book actually had two representations of UI state. The first was built by you, generally defined with data classes and managed by ViewModels. This kind of state is often called application state or app state, because this state controls the behavior of your app as a whole and is how your app sees the world. Your Compose app will also have app state, and it will be defined similarly.

The second representation of UI state in framework views lived inside the Views themselves. Think about the framework CheckBox and EditText views. When the user presses a CheckBox or enters new text in an EditText, that input immediately updates the UI, whether you want it to or not.

The fragmentation of state with framework views means that one of the important responsibilities of your UI code so far has been keeping your app state and View state in sync. If you are using a unidirectional data flow architecture, for example, your app will take in events, update its model, generate new UI values, and then update the UI. But when views have their own state, it is possible for events to short-circuit this flow and update the UI without your consent – possibly incorrectly.

So, when using framework views, you have to ensure that your UI updates as expected, which sometimes means immediately undoing state changes the view makes on itself. This back and forth shuffling of data is hard to manage and is the cause of many UI bugs in Android apps.

Compose is different. In an app created with Compose, UI state is stored in only one place. In fact, Compose does not store any UI state of its own. Instead, you are in complete control of your UI state. Take the Checkbox composable you are using in Coda Pizza:

    Checkbox(
        checked = true,
        onCheckedChange = { /* TODO */ }
    )

If this were a framework view, you would likely expect checked to set the initial checked state of the checkbox and onCheckedChange to be called whenever it changes between states. But in Compose, the semantics are a little different.

The checked parameter defines whether the Checkbox is currently checked. You hardcoded this value to true, so the checkbox is permanently in the checked state – unless you change your code. As you might guess, this is not really how developers design their checkbox composables. Later in this chapter, you will instead set this parameter to a variable, allowing your composable to update when the variable providing its value is reassigned.

Meanwhile, onCheckedChange is called whenever the Checkbox requests that its checked state change. In practice, this means that onCheckedChange is called each time the user interacts with the Checkbox, indicating that the user wants to toggle the box’s checked state.

Generally, this lambda is defined so that it updates the input for checked with the new state – but it does not have to. Which is good, because in the finished Coda Pizza, you want the user to pick where the topping goes – you do not want to immediately toggle the state of the Checkbox.

All of this explains why your checkboxes are currently ignoring user input: Right now, you do nothing when the component requests that its state change, so the checked state of the boxes never changes.

By the way, this philosophy of state is why Compose is referred to as a declarative UI toolkit. You declare how you want your UI to appear; Compose does the heavy lifting of not only setting your UI up the first time but also keeping it up to date as its state changes. Your composables will have a live connection to any state they reference, and changes to their state will update any consumers of that state object with no extra effort on your part.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.80.123