CHRIS ARRIOLA: Jetpack Compose is a declarative UI framework.
You describe what your UI should contain,
and Compose handles the rest.
This way of writing UI is very different from views.
In this video, we'll cover the difference between the two
and how you can shift your thinking
to build apps with Compose.
[MUSIC PLAYING]
With Views, you describe step by step
how to get your UI to look a certain way.
You do this by defining UI in XML,
finding views from XML in code, and then calling
setter functions to get your UI to look the way you want.
With Compose, you no longer have to write XML.
UI can entirely be described in code in Kotlin,
taking full advantage of Kotlin constructs.
Constructing UI by describing what, not how,
is a key difference between Compose and Views.
It's what makes Compose much more intuitive to work with.
Let's take a look at a sample survey app called Jetsurvey.
The screen shows a single choice question
the user has to answer.
Once they make a selection, they can then
proceed to the next question.
To understand how to think about building this in Compose,
let's first look at how we might build this using Views.
To simplify things, we'll look at a single component
in the screen.
A single answer in the survey.
This component is composed of an image, some text,
and a radio button all arranged horizontally.
In Views, these elements would all be defined in XML.
To populate the views with UI state,
we would have to obtain a reference
to each view in Kotlin or Java in our fragment
or activity using findViewById.
After obtaining references, we would then mutate each view
by calling setter functions like setImage or setText
to display the desired UI state.
When state changes, for example, when a user selects an answer,
the view that was interacted with would appear selected.
In our example, when a user selects
an answer in the question, we also
want the Next button to be enabled.
So if we want other views to update
as a side effect of a view being selected,
we would have to set a listener to that view,
and explicitly mutate other affected views.
But having to manually update views when
state changes is error prone.
It's possible to forget to update a view
with its dependent state.
And it's also easy to create a legal status
when multiple updates conflict in unexpected ways.
What if your app goes through a configuration
change like a screen rotation?
And in the process, you might correctly
remember the selection from the user.
But you might forget to re-enable the Next button.
Synchronizing state changes throughout the lifespan
of an app is a recurring challenge
when working with Views.
This problem also increases in complexity
as the number of views and dependent states
grow in your app.
It's a solvable problem.
But it's a common source of bugs.
Let's switch gears and see how we
can think about building this component in Compose.
In Compose, we would construct the UI in a similar fashion--
in a container arranged horizontally
with an image, text, and a radio button.
Instead of writing this in XML, we would define our elements
directly in code, in Kotlin.
Doing it this way, we no longer have
to jump between XML and code as the UI would already
be declared in code.
In Compose, UI elements are functions, and not objects.
This means you can't find a reference to them,
and call methods to mutate them.
Instead, UI elements are entirely
controlled by the state or arguments that you pass.
Here, we are just describing what our UI should look like.
No calls to find view by ID, setImage, or setText.
Our UI is described succinctly in the functions
we are calling.
To display the UI state that we want,
we're passing the answer's properties to the image
function, to the text function, and for now let's
just pass false to the radio button function
which shows it as unselected.
Another important distinction here from Views
is that tapping this answer will not show the item as selected.
This is because we're always providing false to the radio
button, meaning that it will stay unselected regardless
of user interaction.
Unlike in Views, the radio button
doesn't hold its own state that automatically
changes due to a user event.
But rather, the radio button state
is controlled by the values that are provided into it.
This is what we mean by what, not how.
We're declaring what our UI should
look like by providing the necessary states
where our UI functions.
But we're not telling Compose how
it should render that state.
So if state controls the UI, how do we
go about updating state to update the UI?
In Compose, we do that through events.
When a user interacts with the UI element,
the UI emits an event such as on click.
And the event handler can then decide if the UI
state should be changed.
If UI state changes, the functions, or UI elements,
that depend on that state will be re-executed.
This process of regenerating the UI when state changes is
called recomposition.
The process of converting state into UI and state changes
causing UI to regenerate is at the core of how Compose
works as a UI framework.
Let's revisit our example and update our implementation
so that the radio button gets toggled when it's clicked.
First, let's define a Boolean variable called selected,
and pass that into the radio button function argument.
Next, in on click event handler, let's
change the selected value to be the opposite
of its current value.
This way, when it's clicked, it toggles the selection state.
With this change, we should now see the radio button being
toggled when clicking on it.
Notice that I left out the implementation
of the select variable because for this to work,
we have to use a special state object, which
we'll cover in the next video.
In a production app, the state of the radio button
should come from the answer state object.
But we kept it like this to showcase
how radio button state works.
To summarize, to think in Compose,
we declare what we want our UI to contain,
but we don't tell it step by step how to do it.
Unlike views.
We use Kotlin functions to represent our UI elements.
We pass in state to control UI.
And we use events to update state,
which in turn updates our UI.
This was a really high level overview
of how to think in Compose.
But there's so much more to learn.
For instance, how do these Kotlin functions work?
What does state look like?
What are the different components provided in Compose?
We'll answer those questions in the upcoming episodes.
Check out the resources below to learn more.
If you like this video, go ahead and like, share,
and subscribe to the Android Developers Channel
to see more videos on Compose.
I'll see you in the next episode.
[MUSIC PLAYING]