Jetpack Compose

Hi, my name is Romain Guyand I work on the Android Toolkit team and today I would like to tell youabout Jetpack Compose.

So if you haven't heard about it, Jetpack Compose is our next generation UI Toolkit, written entirely in Kotlin to build high quality applicationsfor Android easily and quickly.

But the best way for you to understandwhat Jetpack Compose is and why it's differentfrom the existing UI Toolkit is to look at a little bit of code.

So we'll start with this.

It's a function, it has a single annotation called @Composableand that's pretty much all you need to create a new widget, what we call composables in the Compose world.

You don't have to extend a class, you don't have to overwriteconstructors or methods.

You create a function or methodand that's it.

It can be private, public, whatever you want, it's just a function.

So then to actually generatethe UI from that, you're going to take some input.

So in my example, I want to produce a label for a product.

So I take my product as a parameterof the function, once again, very simple, just a function.

And from then on, I can dowhat we call “emit the UI.

” So I'm going to invokeanother composable function, this one is one of the defaultcomposable functions that are part of Jetpack Compose, it's called Text.

It just creates a label onscreen.

And the text contains a stringthat's built from my product.

One thing that's interesting to noticeis that composable functions can only be invokedfrom composable functions.

So in that sense, they're like suspend functions if you're familiar with coroutines.

@Composable changesthe type of the function, and you can only call themin the right context.

One way to think about itis that your composables are just functions that take dataand transform it into your UI, so your UI is a function of the data.

And that's what we wantwith this function paradigm, not only because it's simplerto write the code, it's simpler to refactor, it's also very easy to reason about.

So we really want the data to flow down from your business logicdown to the functions.

What's powerful about choosing Kotlinto write your UI this way is that you have access to all the features of the Kotlin language.

So let's say, for instance, that we want to only display our label when the quantity of the productis greater than 0.

We don't have to tell Composehow to do this.

We don't have to do things like, okay, let's find this label, if it's visible, let's make it invisible.

If it's not visible, let's make it visible and so on.

Instead, we just tell Compose what we want and you can see the codeon screen, super simple.

I just say, “Okay, if the quantityis greater than 0, there's a label.

Otherwise, there's nothing.

” And Compose will take careof everything else.

And whenever the valueof the product changes, Compose will re-invoke my composable, we call that “recomposition, ” and will reevaluate that logicand will take care of updating the Tree as needed.

So you don't have to worryabout removing and hiding the items.

Compose does everything for you.

And of course this worksin complex situations.

Let's say here I have a for loopto create a column of labels.

If the quantity updates for the product, the number of emitted items will change but I don't have to do anything.

Compose takes care of all of it for me.

Alright, one thing– one other thingI want to talk about is state.

So most of the time you want to operateonly on input parameters and hopefully, immutable parametersto your function but sometimes you want a bit of state.

So here, I have a list of productsand I want the user to be able to filter their listbased on something they type on the query.

So to do this, I start by creating a state.

This is just a string and I can usethis convenient function called state, and I can use it as a delegate.

So it creates a state objectthat Compose will remember.

We say that Compose memorizes it.

Then I can create a TextField.

I can give the filter stringas the initial value to display inside the TextField.

And the TextField can also call a lambda whenever the userenters something inside it.

So in that case, I supply a lambdato onValueChange and inside the lambdaI will update the state.

So whenever the user types something, my lambda is invoked, I update the filter, and Compose will trigger a recompositionwhich will update the displayed value inside the TextField.

And then using that filter, I can go through the list of products and just display the onesthat match the query.

So once again, when the usertypes something into the TextField, a recomposition will happenand my loop will automatically re-execute.

And that's all you have to do.

Again, no callbacks, no clean up, no setup, no listeners, nothing.

You just describewhat you want the UI to be, not how you want it to update.

Alright, so here's howTech Compose works.

So there are two parts to Compose, first on the development host where you write your code.

It starts with the Kotlin Compiler.

We use a lot of features of Kotlin, for instance, trailing lambdas, you may have noticed themoperating the examples.

And even though we use an annotation, we don't use an annotation processor.

Compose uses a Compiler Plugin.

So it works at the typing front system, at the type system level and also the code generation levelto do its magic.

And then finally we have Android Studiothat you all know and love and we have some Compose-specific toolsinside of Android Studio.

Now on your device, we have the Compose Runtime.

At its core, Compose doesn't knowanything about Android or UIs.

It just works on Treesso we could actually emit other things than UIs with Compose.

And then on top we havethe Compose UI Core.

That's your input management, measurement, drawing, layout.

Then we have the foundationthat's your standard layouts, like rows and columnsand default interactions.

And finally, we haveMaterial Design components.

So we have an implementationof the Material Design system so if you choose Material Designin your application, everything that you needfrom Material Design will be available out of the boxwith Compose.

So let's take a look backat Compose so far.

We announced it a year ago at I/O '19.

We also then movedall the development into AOSP.

Now all the development is in the open, you can follow along and you can even contribute if you want.

But it was only the source code.

If you wanted to play with Compose, you had to build Compose yourselfbecause we are not quite ready for prime time yet.

A few months later, at Android Dev Summitwe announced the Developer Preview 1 of Jetpack Compose.

You could downloadthe latest version of Android Studio and you could easily create new projectsand start leaving us feedback.

And since then many of you have done soand we've made major changes to Compose and we think that it's betterthan it's ever been.

So please keep that feedback coming.

So today, we are launchingDeveloper Preview 2 and that's available right nowon developer.

android.

com.

So please give it a try once again.

And if you haven't done so, you will be able to look at tutorials to learn Compose.

Now what's interesting is what happenedbetween Developer Preview 1 and Developer Preview 2.

We started doing biweekly releases, so I believe we've done 12 or 13 releases since thenthat some of you have decided to use and we want to thank you for your patience because we've made major API changesand you had to do a lot of refactorings in your test applications.

But that gives us the abilityto quickly iterate on the feedback you are giving us and once again, Compose is that much better because of it.

So today, I would like to take a lookat some of the things we've done over the past few monthsand also address some of the questions that many of you have asked uswhen we first announced Compose.

If you watched the Android 11 Launch Keynote this morning, you've already seen a demowhere we presented some of the tools that we have for Jetpack Compose.

If you haven't, you should watch that video.

But if not, here's a quick summaryin one screenshot.

So in this screenshot, you can seethe embedded emulator on the left, it helps you run your app side by sidewith your code.

On the right, you can see a previewfor Jetpack Compose composable functions.

So as you make tweaks to your code, you can see the updates in real time to your widgetswithout having to rerun the app every single time.

The preview can also be interactiveso you can even test the logic of your widget without running the app.

Finally, those previews are availablein the inline documentation, you can see that in the pop-up.

So when you do code completion, for instance, you can see what the widgets, the composables look like.

And we have many more ideasof what we want to do for the tools.

So stay tuned, the teamsare hard at work so there is a lot morecoming in the future.

Alright, so first I want to talkabout Modifiers.

So when we first launchedDeveloper Preview 1 [inaudible] modifiers were present, but they were not used that much.

And also they were a bit confusingbecause what you could do with modifiers you could also dowith regular composables.

For instance, paddingused to be a composable.

But we figured that using paddingfor instance as a composable was creating too much nesting.

So now we've moveda lot of features to Modifiers.

Modifiers decorate a single element.

And those decorationscan be layout parameters, metadata or additional behaviors.

But the best way to understand modifiersis to look at an example.

So here, I have an image.

You can see at the topthat I've created a state.

It's a simple circular shapeand you can see I'm using a slightly different variantof the state function that we already saw.

It uses destructuring assignmentto get not only the value but also a lambda that we can useto modify the value, and you will see why in a little bit.

So first, I use an image composableto display my image resource.

And then I have a single modifier called size, it sets the widthand the height and you can see on the rightwhat the image looks like with its fixed dimensions.

Then we can add a second modifier, padding.

Now the image is in set within the boundsof the image composable.

Then we can add a drawShadow modifier.

So the drawShadow modifier is interesting because it is made itselfof multiple modifiers and you can see it clips the image.

So here I'm using my circle shapefrom my state at the top to not only draw a circular shadowbut also to clip the content of the image to the circle.

Then I can use drawBorderto draw a circular border so I still use the same shape.

I use one of the colorsfrom my MaterialTheme.

But also I can stack multiple modifiersof the same type so I can add a second border or even a third border.

And already you can seethat adds something that's much more interesting.

We started with this very simplerectangular image.

Now we have a shadow, we have circular clipping, and we have multiple borders.

I can also make the composable interactiveso here I use a ripple, a Material Design ripple.

So every time the user taps on the image, I will automatically get the nice ripple effect, the animation will be handled for me.

and it's just a one line modifier.

I also use a clickable modifierto add interaction to my image.

So in this case, I call my set shapelambda that was given to me by the state functionto toggle back and forth between the original circle shapeand this new cut-corner shape.

So now, just using modifiers, I started from an image, a static image, and now I have this visually complexinteractive piece of UI.

And that was super easy to do.

Alright, one of the things thata lot of you have asked us about when we first announced Composewas what about Recycle View or you know, for folks like mewho started a long time ago, what about List View? You called out rightly sothat all of our examples were built without usingone of the fundamental elements of Android applicationsthat we use everyday on our phones and that's this kind of Recycle List.

You can see on the screen I have my demowhere in my app, my shopping cart is made of multiple itemsand I can scroll through them and have this recycling list of items.

We start with a composable function.

You need to take a list as an input.

In my case, I could takea simple Kotlin list or a mutable listbut I'm using LiveData.

We also provide supportfor RXJava and Flow.

So when you use LiveDataor RXJava or Flow, you need to observe the data streamas a Compose state.

When we pull the extension functioncalled observeAsState, you can see it in action here.

I can call observeAsState, I give back a state object, here called productsand I can pass the state to my AdapterList, that's the nameof the recycle view in compose.

And then using a trailing lambda, every time that the AdapterList needs a new item or to replace an item, I can just describe the UI I want to emit.

So in my case, I will createa shopping cart item based on the productthat I received as an input.

And inside I want a 3D model viewerfor the nice 3D animations.

And that's it, you don't needto write an adapter, you don't need to do anythingmore than that.

As soon as the LiveData object changes, if the number of itemsin your list increases or decreases, or the value of any of the items changeswe will automatically recompose everything, re-invoke your trailing lambda for the AdapterList, and the UI will update.

It's not more complicated than this.

ConstraintLayout is oneof our most powerful and most popular layoutsand that was one of the main questions we got, again, when we announcedthe Developer Preview 1 and Compose at IO, you wanted to knowwhat about ConstraintLayout, how will this work in Compose? And that's actually a very good question.

It stems from the fact that in Compose, because we use functions, you can't grab a reference to view, so how do you describe constraints between different elements? So I'm going to show you how to useConstraintLayout with Compose.

Now we're going to use this small examplein the bottom right.

That row at the bottomhas a couple of buttons, it's decrease and increase buttons.

Then we have some text, we have a little color swatch and we have another label.

So let's take a look at how it works.

So first in @Composable, we create a ConstraintLayout and that ConstraintLayoutneeds a ConstraintSet.

Those used to be definedan XML or in code but now they are entirely in code.

But because it's an object, you can of course make that a constant, you can pass it around, you can do whatever it is you want.

Here, we're going to create it inline.

So to create a new constraint, use this tag function.

You give it a tag, the tag can be anything you want, it could be a string.

In that case, just a regular Kotlin object.

And in that tag, we can declarethe constraints themselves.

So in this example, for the first button, the decrease button on the left, I want to constrain the left edgeto the left edge of the parent and I also want to center it vertically.

And then all that's left to dois emit the button, itself, and to be able to map it to the constraint we just created, we use a tag modifier.

So we just assign a tag to the composableand ConstraintLayout will do the rest.

Now because tag returns a constraintas an object, we can use that as a reference in other constraints.

So for the next buttonthat goes to the right of our first button, we create a new tag.

And for the left constraint, we just use the right edge of the decreaseConstraintthat we just created and the rest is exactly the same.

We create our button, we assign a tagand ConstraintLayout will match the constraint to the composable.

What's really powerful about doingall of this from code is that you can add a little bit of logic.

So if we fast forward a little bit, I've added the labels and I have this little color swatch, that little red dotthat you see at the bottom.

That red swatch is not visiblein every item of my list.

It only appears on some items.

So then how do I align the last labelto the right of that swatch if that swatch is not always there? So this is how you do it.

I create a new Constraintsand for the left edge, I set constrainTo and here I can entera complex expression.

So here I say, “Okay, if I have a swatch, I want it to be constrained to the constraint of that swatch.

” Otherwise, I want to use the constraintof the label that came before.

So this is much more convenientthan doing the equivalent using both XML and code.

Another thing a lot of youhave asked about is Animations.

So I want to show you how animations workwith Jetpack Compose.

On the screen right now, you can see some of animations I have built into my demo.

Whenever the user selectsone of the items in the shopping cart, for instance, to select multiple of themto be able to delete them quickly, I animate the radiusof the different corners, I animate an overlay on top of the itemand I animate a little check mark.

So let me show youhow this works with Compose.

So first we're going to create stateinside our item to track the selected state of the item.

So once again, I usethe destructuring assignment.

So I have selected as my state valueand I have onSelected my lamba to be able to changeand update that value.

Then at the bottom, I could usea Toggleable composable function.

This will just– it's just a helperto be able to do this selection easily.

So I give it the selected stateas the value, and whenever the value changes, I tell it invoke my onSelected lambda.

Then, for the ripple effect, that's built in so I don't have anything to do, just Modifier.

ripple.

Here's where things get interesting.

To animate the radiusof the different corners, all I have to do is usethis animate function.

And I pass it a value, and as you can see, that value is itself based on my selected stateso I say, “If the item is selected, I want a radius of 48 dpfor the top left corner.

Otherwise, I only want 8 dp.

So whenever the selected state changes, recomposition will happen, a different value will be passedto the animate function, and the animate functionwill take care of everything else.

It will kick off the animation, picking up where you left off, it's fully interruptibleand it's based on physics.

So then after calling animate, I have another state value that I can then passto my rounded corner shape.

I can just assign those values directlyto the different corners, and that's it, you don't have to havelisteners and callback, there's no set upand there's no clean up to do.

It's that simple.

Of course, like I said, by default, we use physics-based animations.

We can use twin animations if you preferand there's a lot of things you can controlthat I won't show you today.

This is another example, same conceptbut this time to animate the alpha.

So instead of passing the valueto the radius of the rounded corner shape, I just pass the alpha that I'm animating with the animate function.

I pass as it as a color of the surface.

Alright, next up is Interop.

You can see here in the demothat I have this list of items and in every item, there is a surface view to be able to render this complex 3D scene.

They are also fully reactive.

So whenever I click the swatchin the top item of the list, you can see thatthe color of the 3D object updates in real time.

And this is somethingthat we really care about.

We got really inspired by Kotlin.

Kotlin is great because if you haveyour existing Java-based application, you can start adding Kotlinat your own pace.

You don't have to rewritethe entire application.

And we wanted to doexactly the same for Compose.

When you want to adapt Compose, you can just start adding Compose bit by bit, a new screen, a new part of a UI, just however you want to do it, it's going to work.

So let me show you how to put viewsinside of Compose.

So we start by creatinga new composable function.

This is my 3D viewer, it takes my product as an input.

Then I have a bit of state, not all viewers, just the 3D viewer, itself.

You don't really have to worryabout what it is exactly.

What's interesting is at the bottom.

I call this composableAndroidView function.

And I give it as a parameter, an ID for an XML layout.

That XML layout contains a surface view.

When it's done inflating, AndroidView will invoke my trailing lambda, it will give me a reference to the view that was inflated, and I can then cast it as a surface view, and from there, I can create my model viewer and tell it render into that surface view.

Of course, to render the 3D animations, I need to be able to refresh the content of the surface viewin every frame.

So to do this, I can use onActiveand onDispose.

So onActive is going to be invokedthe first time your composable is added to the UI Tree if you want.

This is a great placewhere you can do some set ups or in my case, I'm going to set upa call back for the choreographers so I can get it invoked on every frameevery time the screen refreshes.

Of course when the composabledisappears from the tree, I need to be able to stop that callbackso I can use onDispose to do my clean up.

So when you're part of a recycling listlike AdapterList, this is really powerful to make surethat you're doing the right thing.

Now to react to data changes, so when I change the color of the product, I can use onCommit.

So onCommit takes as a parameterwhat I want to track.

So I want to track my product, itself.

And in onCommit, I'm just going to lookat the 3D object in the scene and change its colorbased on the new value from the product.

And that's it.

It's really simple.

If you want to use a map view, a camera view, a surface you like I showed you or any type of view, you can incorporate themin your Compose UI just in this way.

Last but not least, Testing.

This was also oneof the first questions we got.

So once again, in Compose, because you just invoked functions, you can't take a reference to the widgetsand we don't have the concept of ID, so you can't do a 'find you by ID.

' So in our example, how do we test, let's say, those two buttons to increase and decrease the quantityof the product in our shopping cart? So let's take a look.

To do this, we use a conceptcalled semantics.

Semantics are a way to add metadatato the tree of composables.

This is what we use, for instance, to drive accessibility but this is also at the core of testing.

So for instance, here in my examplein my shopping cart item, I use the TestTag composable.

This creates a semantic nodethat contains a tag.

It's a way for me to identifythat part of the UI and you can see it just containsmy button that I want to test.

So once we have that semantic node, we can move over to the Unit test, just a regular @Test function.

I create some test data, so I have a product, I have the quantity = 2.

I also need to create my logicso this is a lambda that will simply decreasethe quantity by 1 every time the user clicks the button.

Then I can set up my Test UI, I just invoke my shopping cart item and then give it the dataand the lambda I just created.

Finally, here's the interesting part.

I can use findByTag to findthe part of the tree that we just tagged inside our composable.

And from then onI can do a lot of things.

I can query whether or notit's displayed, I can check its state, I can check a value, or I can perform actions.

So here I perform two clicks, and finally, at the end, I make sure that the quantityis now 0 instead of 2 after two clicks.

The best part is Composeis designed with testing in mind so all those features come built in.

You don't need somethinglike Espresso, for instance.

This runOnIdleCompose that you seethat I use at the bottom is part of the default APIs.

So that's it for today, that's everything we've been up to– well, of course, there's a lot more–over the past few months.

But now I want to look ahead a little bit.

So we are releasingDeveloper Preview 2 today, and later this summer, we are going to release our Alpha release of Compose.

For us, Alpha is when you startadopting Compose inside your application.

Some features might be missing, we have to catch up with 15 years of developmentin the existing APIs, after all.

But there should be enoughfor most applications out there.

Some of our APIs may still be experimentaland there might be a few changes ongoing after Alpha.

But we really want to startplaying with it and give us all the feedbackthat you may have because next year, we want to releaseJetpack Compose 1.

0.

So if you haven't done so already, please visitdeveloper.

android.

com/jetpack/compose.

There you can find hwo to downloadand install the Developer Preview 2 with the latest version of Android Studio.

You will find tutorials, codelabs and so on.

You can also read the samplesthat we put on GitHub.

And more importantly, you can come chatwith the team on Slack so you should join the Compose channelon the Kotlin link Slack.

You will be able to talkwith various members of the engineering team.

This is a place where we gathera lot of your feedback.

This has been immensely helpfulto improve Compose in the past few monthsand it's so much better than it was when we started.

You'll also be able to chatwith the rest of the community and everybody's incredibly helpful there.

If you have future requestsor if you find bugs, as I'm sure you will, please use the Issue Tracker that's listed here.

This is the same Issue Tracker we useso we look at it all the time.

Finally, if you want to see what's coming, you can look at all the changesthat we make daily on AOSP at android-review.

googlesource.

com.

You can just watch everything happening, and if you want, you can even contribute.

So that's pretty much it for todayand I would like to thank you, all of you, for all the feedbackthat you've been giving us.

But before I let you go, I just wanted to say that I've been working on Androidfor close to 15 years and usually I do not usethe word “excited” lightly when I give a talk, but frankly, I don't think I've ever been as excitedabout the future of Android UI as I've pretty much ever been– well, maybe on my first day on Android– so I'm really looking forwardto what you're going to do with Compose so please keep the feedback coming.

Thanks.

.

Hãy bình luận đầu tiên

Để lại một phản hồi

Thư điện tử của bạn sẽ không được hiện thị công khai.


*