Using Jetpack libraries in Compose | Session

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hi everyone i'm manuel and i'm here with ian to talk through how well the advac compose our new ui toolkit works with the existing jetpack libraries you might already be using in your apps one of the most important parts when designing compose was that you should be able to incrementally adopt it with your existing apps without rewriting everything from scratch that means your business and data layers below the ui layer can be used with a shiny new compost ui let's take for example this app bloom bloom is a home garden shopping app that gives users the ability to search through a huge set of plans and look through previewed collections of related plans let's dive into how we could write this screening compose through using views and xml all that with the power of jetpack in bloom's case we've taken heavy advantage of many other jetpack libraries if we take a look at the architecture of the app bloom uses room to store the plants in the database paging to load them in memory efficient chunks view models for handling ui logic kotlin cordless flows to expose state and data between each layer and health as the dependency injection solution bloom's home view model serves two main purposes first it provides a separation between the states that is exposed to the ui and how that state is produced it is the view model that is responsible for handling the business logic of the home ui second as it extends the jetpack viewmodel class it survives configuration changes ensuring the latest data is instantly available the paste list of plants is exposed from the ripple layer and the rest of the ui state of the screen consists of the collections of related plants and signals in case the page is loading or an error needs to be shown looking at the home screen we could break it down into a number of separate composables for each part of our ui it's taking in only the data that it needs jumping into the implementation of home screen we can get an instance of the home view model in a composable by using the viewmodel method this method is doing two things for you first it is automatically scoping the view model to the closest new model store owner if we were to put our home screen directly in an activity it would use that if it was in a fragment it would use the fragment scope instead secondly it is using the default factory for an android entry point annotated activity or fragment case health has already installed itself as the default factory so our health powered viewmodel works right out of the box if you aren't using health or any other dependency injection solution you will need to create the viewmodel factory by hand and pass that into the viewmodel function in compose it is a good idea to prefer compostables that don't hold state for better reusability and testability we call them stateless composables as opposed to stateful ones that do hold internal state in this composable home screen is retrieving an instance of home view model inside the function itself which makes it a stateful composable to make it stateless we should provide the viewmodel as a parameter instead in this way we delegate the responsibility of obtaining the viewmodel to the parent so that this composable can focus on emitting ui once we have an instance of the viewmodel we can collect the ui state flow using the collect state function this will re-execute the composable where the state is read and will update the ui accordingly with the new values if you use live data or rx java don't worry we got you covered as well with the observer state and subscribe as state functions we said that we have a lot of plants in bloom so using paging to load those scene in chunks makes a lot of sense the paging compose artifact makes it possible to transform our flow of paging data into state that we can use in compose with the collect as lazy paging items method with that we can easily display them using at least a column also by looking at load state we can easily add our own loading composable to indicate when the data is refreshing and even when we get to the bottom of the screen while more data is being appended onto our list and now on the home screen we can call plant list with the data coming from the viewmodel before moving on let's post acknowledge that we've been using a lot of jetpack libraries in our composed ui without modifying our viewmodel or changing any other layer of our app that's cool isn't it looking at the design of our app there is a piece of ui that we might want to reuse in other screens and that's the browse collections carousel that can be reused for recommendations on a planned digital screen as you can see here what's interesting about this carousel is that when you tap on an item it expands to show plans related to that collection in its implementation the carousel needs logic and internal state to expand or collapse itself as well as handling logic to allow only one collection to be expanded and go to the plant digital screen when the user taps on a plant where do we put that logic in a view model well that's not possible for reusable ui components let's dive into this to make collections carousel reusable we follow compose best practices by passing state in and exposing events out encapsulating the logic and controlling the state of decomposable in a class is a good way to protect the composable from displaying an inconsistent ui and avoid repeating the same code in different places for the state of collections carousel we can create a regular class called collections carousel state that takes in the collections as a parameter it exposes information about whether the carousel is expanded the selected collection and the plans to show and it encapsulates the logic to update the state when a collection is clicked in a single entry point method on collection click this state is now provided to the composable as a parameter that colors of collections carousel need to create and manage for events collections carousel takes one extra parameter a lambda that is called whenever the user taps on a plant but you might be wondering why do we have collections carousel state as a regular class and events to indicate user interactions instead of having all of that in a view model as a rule of thumb you would create a view model to host state handle logic and process events when the composable is close to the root level of the screen for example a home screen or loading screen composable when that's not the case for example for reusable composables like a carousel don't use a view model instead create a regular stateholder class to manage state and expose events to the calling function this is because view models are scoped to either an activity fragment or destination of an application graph therefore you can only get one instance of a viewmodel type in that scope the benefits for viewmodels at screen level composables are that they can survive configuration changes data can survive process death via safe state handle it is a better place for state whose life cycle matches the screen and they have an already built-in coding scope that you can use to trigger your business logic going back to the code as common screen state is managed by home view model cursor state should be part of the ui state that the view model exposes then that's passed to collections carousel but what about the navigation event what should we do with that and what about the home screen itself we should be able to apply the same testability and preview capabilities to the whole screen right that's absolutely right we want to be able to write tests against our home screen and pass fake data to a preview without worrying about our view model and collecting state it's easy enough to make those changes to our home screen just add the ui state the flow of the paged plants and an on plant click lambda as parameters while this might not seem like a big deal we've just pushed the call to view model and collective state up a level it makes a big difference when thinking about where this home screen is going to go in relation to everything else in your app if bloom was an app with just a single screen we'd be able to use the set content function to set our composable directly in the activity but our mocks show a much more complicated app so adding our composable directly to the activity might not be the right approach a very natural migration path for an existing app when starting to adopt compose would be to migrate one screen at a time if you're using fragments for instance this home screen could actually be the only content of your home fragment creating the compose view directly in oncreateview in this type of approach you'd use an apis like fragment scenario to test your whole fragment once every screen in your app is just a wrapper around a reusable testable composable the next step would be to tie all those screens together with navigation compose the jetpack navigation component was built from the start as a generic runtime that knows nothing about any type of destination this abstraction was then used to build the navigation fragment artifact and more recently the navigation compose artifact this shared runtime means that each of these implementations got out of the box support for building a navigation graph of the screens or destinations in your app via colin dsl automatic scoping of the life cycle view models and save state to each destination deep linking returning a result and integrating with the system back button in navigation compose there's two main pieces you need a nav controller and a nav host the nav controller follows the same pattern we used for the collection's carousel state by allowing you to create the stateful nav controller as a separate object from the nav host that takes the nav controller as input this allows other components outside of the nav host to react to the current destination changing by using the nav controller as the single source of truth for the state this is helpful when setting the selected item in a bottom navbar for instance the nav host composable is responsible for adding your composable destination into the compose hierarchy it's here where you define your navigation graph via a kotlin dsl this is a map of all possible destinations in your app so for our home screen we can create a home composable destination you'll note that we declare a route on our home screen this is the unique path that you use to navigate to that destination since this is the main screen of the app we set it as the start destination of our graph we've needed to make one change to our code though instead of using view model we're using the hilt navigation composes hilt nav graph view model method like i mentioned navigation automatically scopes your view models to the individual destination but since the destination isn't an android entry point activity or fragment it doesn't have hilt's factory as the default factory the hilt nav graph viewmodel method is a convenient wrapper around viewmodel that ensures that the right factory is always set for you note that we didn't need to change our home screen at all it's totally unaware that it is being used within navigation compose and can still be tested independently of course the big benefit of navigation compose comes when you have more than one screen that's when the ability to scope the save state and view models to the individual destination ensures the state is created only when is needed and is removed only when you pop the destination off the backstack in the case of bloom the tiny images on the plant list or the expanded carousel should just be a preview for a detail screen that really gives the user an idea of what they can get for their garden the first step is to build the plant details screen just like our home screen we should build our plant detail screen as a stateless component so that we can use previews and test it in isolation right from the start you'll note our collections carousel makes another appearance building reusable components means not only a more consistent experience for users across your app but also helps when building out new screens next we need to add the plant detail screen to our navigation graph this is just another composable destination but there's one difference here compared to our home screen we need to know what plant the user selected the routes in navigation have a lot in common with web urls and that they're designed to serve as the address of the content we show this means that our route isn't just plant but plant with the id of the plant we want to show using this placeholder syntax for our plant class the id is an integer so we declare it with the int type now we could extract the id directly from the backstack entry the nav host passes to our plant detail destination but we really want that id in our plant view model not here to accomplish this we can use another api that's part of jetpack view model save state handle a save state handle is really just a fancy key value map but the important thing is that it's automatically populated by the arguments we put in our route this allows our viewmodel to pass that id directly through to our repository to retrieve the plant details and provide that observable flow to the ui this means that if background loading updates the price of the plant or otherwise changes our single source of truth our plant detail screen will automatically recompose with the new data thanks to manuel's work on making the home screen stateless we already have exposed a lambda that's triggered when the user taps on a plant our home screen destination then implements that landa calling navigate with the route of our plant detail screen filling in the id the nav controller takes care of the rest of it saving the state of the home screen and swapping in the plant detail screen hitting the system back button automatically takes you back to the home screen in exactly the state you left it in we're just scratching the surface of what you can do with jetpack compose and all the integration points with other jetpack libraries if you want to learn more i'd strongly recommend reading through our guide on compose interoperability and the guide specifically around navigating with compose in our docs for practical examples check out all of our compose samples and a realistic example of converting an existing app to compose in the sample app tv all the links are in the description whether you're working on a brand new project in compose or adapting an existing project jetpack is here to help thanks [Music]
Info
Channel: Android Developers
Views: 16,119
Rating: 4.935185 out of 5
Keywords: purpose: Educate, type: Conference Talk (Full production), pr_pr: Google I/O, Jetpack, Jetpack libraries, Jetpack Compose, Android Jetpack Compose, Android Developers, Android Dev, How to use Android Jetpack Compose, What is Android Jetpack Compose, Jetpack Compose tutorial, Android Jetpack ViewModel, #GoogleIO, Google I/O, Google IO, Google developer conference, Google announcement, Google conference, Google
Id: 0z_dwBGQQWQ
Channel Id: undefined
Length: 19min 8sec (1148 seconds)
Published: Tue May 18 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.