Loading...
Home
  • Tech Blogs
  • Videos
  • Conferences
    • Droidcon News
    • Upcoming Conferences
    • Become a Partner
    • Past Events
    • Keep Me Informed
    • Diversity Scholarships
  • Community
    • droidcon Team
    • How to Hold a Droidcon
  • Android Careers
Sign In

Global CSS

 

Jetpack Compose Interop Part 2: Using Compose in Traditional Android Views and Layouts with ComposeView

 

 
Dai
Senior Android Engineer @Plex
Published: October 26, 2020
Tweet
Share
 

 

In Part 1 I demonstrated how we can use AndroidView to render traditional Views inside our Compose UI. For this part, we are now going to make newly created Compose UI components work inside traditional Views and Layouts with another special class, ComposeView.

Note: Just like in part 1, I am not going to deep dive into Jetpack Compose and I do assume you have some basic knowledge of how to use Compose. However, it should be fairly easy to follow along without knowing too much.

You are probably wondering why would anyone want to put Compose UI into older views. If you are using Compose, why not just use it everywhere 😅. However, just like Kotlin interop, having the ability to progressively adopt something new allows us to overcome the learning curve while remaining productive. We can keep our code consistent but start using Compose in projects sooner. So let’s look at how we can achieve this interop and provide some examples of why it may be useful.

 

ComposeView

Again, this is not a poorly formatted title, but another useful class that, this time, allows us to easily place Compose UI into traditional UI. ComposeViewextends from View so it allows us to use it like any other View in Android with one major difference, we can add Compose UI components using a convenient setContent method.

Let's look at a quick example to demonstrate:

 

 

So here we are creating a new ComposeView and attaching it to a parent container, just like we might do with any View. We then use setContent to render Compose UI, and in this case, a simple Text composable. It’s as simple as that! We can even use the ComposeView in XML layouts too. So taking the same example, let's do that.

 

 

Our activity_main.xml now contains a ComposeView nested inside a LinearLayout. We use this to do the same as we did before, but instead of adding the ComposeView manually we grab the reference and call setContent to add our Text.

 

 

And there you go, we have our Compose UI being treated like a traditional View. This is a little messy though. Mixing the two like this is not great and what if we want to do something a bit more custom.

 

AbstractComposeView

As you start to adopt Jetpack Compose one thing you might not want to do is start flip-flopping between older UI and Compose UI in the same file (like we did in the example above). Doing it like that will start to blur lines between which bits are Compose and which are not as things get more complex. To solve this you might want to create a bit of abstraction to keep things cleaner and in general, hide what's going on under the hood. So let's take the same Text example above but use AbstractComposeView to create our own custom View that will wrap the Compose UI components.

 

 

And just like before, we can then use this either directly in code or in our layout file.

 

 

So now we have a custom MyComposeView component that under the hood is rendering Composable UI, which is pretty awesome!🤩 The benefit here is you will be able to write new UI in Compose and retrofit them to your older screens with a simple wrapper View allowing you to maintain consistency in your codebase, which is particularly useful when you can’t refactor all features and views at once.

 

Taking it a bit further

The problem with the example above is the Text has a hardcoded value. So let’s take the same example and provide the ability to set the text dynamically. I have not added an example to use attrs here but setting a value to the Statefrom an attribute value on initwill work in the same way.

 

 

In the new example, the MyComposeView now exposes a title field that we can use to update the text value whenever we want. I am not going to go into the details here, but just to note, the mutableStateOf function creates aStateobject that when its value is used inside Compose, it will automatically update the UI if the value changes. That’s exactly what we have done in the above example with text = titleText.value. Unlike LiveData you don’t need to explicitly observe and set values. Compose handles this for you.

We can now use our title setter wherever we want to update the title.

 

 

And there you go, we can now set the text for our custom AbstractComposeView without exposing anything from Jetpack Compose into our older Views and Layouts.

But that’s a little boring really. Let’s create something a bit more interesting.

 

Live TV Featured/Recent Channels

As part of our Live TV experience within Plex, we display a horizontal list of recently watched/Featured TV channels. The architecture around how we deliver and display dynamic lists like this within the app is a lot more complex than the example below but let's see if we can implement a basic version of this feature that creates a horizontal scrolling list of TV channels written in Compose but displayed as traditional View just like we did in the previous example.

First off let's define a ChannelCard composable and a Channel data class.

 

 

Our ChannelCard is a simple Card with rounded edges containing a single CoilImage. CoilImage is not part of the standard Compose toolkit and for anyone who is not aware, Coil is an image loading library for Android. We are using this simply to display the channel logo of each channel in the list. If you want to use CoilImage composable to load images in your projects you can find out more here.

The ChannelCardon its own is only going to display a single channel. So let's create a ChannelCardRow composable that will render them in a horizontal list.

 

 

From the above snippet, you can see our ChannelCardRow is a simple lazy horizontal list (row), that creates a ChannelCard for each channel.

Now that we have all our Compose components defined, let’s create our AbstractComposeView implementation that will allow us to display our horizontal list of channels as a traditional Android View.

 

 

As you can see, just like before we are using mutableStateOf for our list of Channel data. Our Content method override then displays aChannelCardRowconnected to the State so that whenever we set the current channels we render them onto the UI.

Now for the final bit, let’s use our ChannelCardRow implementation of AbstractComposeView in our Activity and load in some channels from our ViewModel.

 

 

All wired up and 🥁…

 

Image for post

ChannelCardRow Android View showing Channels

 

And there you go, we have a nice little reusable View that is using the just as reusable Compose UI components under the hood to display a horizontal list of TV Channels. And as you start to adopt more Compose in your app you can remove the traditional wrapper layers as and when they become obsolete.

 

Summary

The point of these blog posts was more to show what is possible for Compose interop. I can provide more details but hopefully, this and Part 1 provide enough detail to get you started and thinking about how you might adopt and interop Compose in your projects as things begin to stabilise. And just to recap:

  1. Use AndroidView to render traditional Views in your Compose UI (Part 1).
  2. Use ComposeView/AbstractComposeView to render Compose UI in traditional Android Views and Layouts.

I’m Dai, an Android Engineer for Plex. All views are my own.

Twitter: @daioio

 

Tags: Android, Jetpack, Jetpack Compose, Views, Kotlin

 

View original article at: 


 

Originally published: October 21, 2020

Android News
Our Engineering Roadmap
Our Engineering Roadmap

By Mark Ng

We just completed our engineering road map for our Android apps at Australia Post. Each year we get together and try to decide on what we are going to do from an engineering perspective for the next 12 months. Each team gets to decide on what should be done now, what they want to complete by the end of the year and whats on the horizon for next year.

By ProAndroidDev -
Android News
Android Activity Lifecycle considered harmful
Android Activity Lifecycle considered harmful

By Eric Silverberg

The Android activity lifecycle is one of the first architectural concepts learned by a new Android developer. Ask any Android dev and they’ll likely all have seen this handy diagram from Google: 

By ProAndroidDev -
Android News
Our Safe Approach to Android Jetpack Navigation in a Multi-Modular App
Our Safe Approach to Android Jetpack Navigation in a Multi-Modular App

By Alejandro Weichandt

It has been a year since we started working on the Android version of the mobile app at Sync. During that year, we faced more than once that moment when we had to choose which path to follow on an Architectural decision. This story is about Navigation.

By ProAndroidDev -
Android News
Custom KotlinX Serializers
Custom KotlinX Serializers

By Jobin Lawrance

Let’s say we have a third-party class that we are using as a type in one of our data class that we want to be serialized, then we have to write a custom serializable for @Serializable to work.

 

By ProAndroidDev -
droidcon News

Tech Showcases,

Developer Resources &

Partners

/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/home-details/EmployerBrandingHeader
EmployerBrandingHeader
https://jobs.droidcon.com/
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/jobs-droidcon/jobs.droidcon.com
jobs.droidcon.com

Latest Android Jobs

http://www.kotlinweekly.net/
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/kotlin-weekly/Kotlin Weekly
Kotlin Weekly

Your weekly dose of Kotlin

https://proandroiddev.com/
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/pad/ProAndroidDev
ProAndroidDev

Android Tech Blogs, Case Studies and Step-by-Step Coding

/detail?content-id=/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Zalando/Zalando
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Zalando/Zalando
Zalando

Meet one of Berlin's top employers

/detail?content-id=/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Academy for App Success/Academy for App Success
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Academy for App Success/Academy for App Success
Academy for App Success

Google Play resources tailored for the global droidcon community

Follow us

Team droidcon

Get in touch with us

Write us an Email

 

 

Quicklinks

> Code of Conduct

> Terms and Conditions

> How to hold a conference

> FAQs

> Imprint

Droidcon is a registered trademark of Mobile Seasons GmbH Copyright © 2020. All rights reserved.

powered by Breakpoint One