Interoperability with Jetpack Compose
Learn how to use Compose Interoperability in your Android app. By Eric Duenes.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Interoperability with Jetpack Compose
15 mins
You’re close to completing your android application, and it’s all written using Android Views. You want to start using JetPack Compose, but don’t want to rewrite all your layout.xml files. Or, maybe you started a project using Jetpack Compose, but want to leverage existing Android Views. What can you do?
You’re in luck — Jetpack Compose offers Interoperability. You can take advantage of this modern toolkit one composable at a time and migrate in and out of your Android Views at your own pace.
In this tutorial, you’ll explore Compose interoperability. You’ll use composables to complete a scorekeeper app that was created using Android Views. You’ll change the playing field and add Android Views to an activity using Jetpack Compose. As you complete this tutorial, you’ll learn about:
- Jetpack Compose Interoperability APIs
- Composable Lifecycles
- Composition Strategy
- Recomposition
The match is about to start — may the best team win.
Getting Started
Download the starter project by clicking the Download Materials button at the top or bottom of the tutorial.
Open the project with Android Studio. You’ll see the following file structure:
The AndroidManifest.xml declares .MainActivity
as the activity to launch after the app starts, and it also contains .ComposeActivity
— which currently does nothing. Using intent-filter
attributes, you’ll be able to launch the main activity for the first half of the tutorial and the Compose activity for the second half. Here’s an overview of the two activities:
- MainActivity.kt was developed using Android XML layout views and view binding. The activity inflates activity_main.xml layout view, and it provides the ability to keep score for the home team. These are the files you’ll be manipulating in the first half of the tutorial.
- ComposeActivity.kt was developed using Jetpack Compose. It will leverage components from VisitorTeamView.kt and provides the ability to keep score for the home team. You’ll be using these files in the second part of the tutorial.
Sync the project. Then, build and run. The app will look like this:
The starter project gives your user the ability to keep score for the home team — but sports matches are usually played by two teams. Using Jetpack Compose interoperability, you’ll add functionality to keep score for the visiting team.
Introducing Recomposition Strategies
Before you start keeping score, consider the lifecycle of a composable.
A composable can go through many changes during the lifecycle of your application. It’s drawn on your screen when initialized and re-drawn whenever the state changes. Additionally, when using Interoperability API, a composable can become detached and disposed of Android Views at different stages of the view lifecycle. As a result, it’s best to identify and set the correct ViewCompositionStrategy
.
By setting the correct view composition strategy, you’re ensuring two things:
- Your components don’t become disposed of while still on the screen. That would be a bad user experience.
- Your components do become disposed of at the right time. Retaining components unnecessarily will cause memory leaks in your application.
There are three view composition strategy options available:
-
DisposeOnDetachedFromWindow
: This is the default strategy, and the component will be disposed when the view is detached. This strategy can cause a memory leak if you callcreateComposition()
. In this scenario, the view will get created but might never be attached, so it won’t have the opportunity to be disposed. -
DisposeOnLifecycleDestroyed
: With this strategy, the component will be destroyed when the owner of the lifecycle is destroyed. -
DisposeOnViewTreeLifecycleDestroyed
: In this strategy, the component will be destroyed when the parent’s lifecycle is destroyed. This strategy is ideal when your component is in a Fragment.
Adding Composables
From the starter project, open activity_main.xml. You’ll add the Visitor Team section using ComposeView
.
After the divider view, add the following code:
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/divider"
/>
You’ve just given yourself an entry point to add composables to your Android View.
Now, open MainActivity.kt and inside onCreate()
, use view binding to apply the composable like this:
//1
binding.composeView.apply {
//2
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindow)
//3
setContent {
//4
val visitorScore = remember { mutableStateOf(0) }
//5
VisitorScreenView(
visitorScore = visitorScore.value,
decreaseScore = { visitorScore.value-- },
increaseScore = { visitorScore.value++ })
}
}
Score one for the good guys… yes, that’s a sports reference. :]
You’ve now applied VisitorScreenView
composable to the Android View. Here’s what you did:
- Using view binding, you’re able to get a handle to
ComposeView
. Remember? You added that to your layout XML file. - Here, you’re setting the composition strategy to
DisposeOnDetachedFromWindow
. This strategy is safe to use here since your composables will be displayed in an activity, and you won’t be callingcreateComposition()
anywhere in your code. - This is the block where you’ll add your composables.
- You’ll keep track of the score with
visitorScore
. This will be stored as state and will be used byVisitorScreenView
. To learn more about preserving the UI state of an Android application, check out Managing State in Jetpack Compose. -
VisitorScreenView
is a composable function that has already been created for you. It contains the view for the visiting team and takes three parameters:-
visitorScore
variable accepts an integer value that will be used to display the score for the visiting team. -
decreaseScore
parameter accepts a lambda function. It will be used to decrease the visiting team score. -
increaseScore
parameter accepts a lambda function. It will be used to increase the visiting team’s score.
-
Build and run the application. You’ll see this screen, and you’ll be able to modify the visiting team’s score.
Abstracting Composables
You’ve now successfully added composables to your view, and you’re keeping score like a champ. But as the game progresses, you realize something… you can track the score, but with your Android Views and composables in the same file, how can you track where Android Views end and composables begin?
To keep things clean, you should separate your composables from your Android Views. You can use AbstractComposeView
to achieve this.
Open VisitorTeamView.kt and add the following code:
class VisitorTeamView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : AbstractComposeView(context, attrs, defStyleAttr) { //1 private val visitorScore = mutableStateOf(0) //2 @Composable override fun Content() { setViewCompositionStrategy( ViewCompositionStrategy.DisposeOnDetachedFromWindow ) VisitorScreenView( visitorScore = visitorScore.value, decreaseScore = { visitorScore.value-- }, increaseScore = { visitorScore.value++ }) } }
VisitorTeamView
class implements AbstractComposeView
. The code should look familiar to you because it’s similar to what you implemented in the previous step.
- Your
visitorScore
variable will hold the score value as state. - Inside
Content()
is where you’ll set your composition strategy and call your composable functions.
VisitorTeamView
class directly from the layout file.
Open activity_main.xml
and replace androidx.compose.ui.platform.ComposeView
declaration with com.yourcompany.skeeper.ui.VisitorTeamView
:
<com.yourcompany.skeeper.ui.VisitorTeamView android:id="@+id/compose_view" ... />
Finally, to complete the cleanup, go back to MainActivity
and remove binding.composeView.apply {}
along with all the lines of code inside of it.
There you have it. All your composables are in the com.yourcompany.skeeper.ui
package.
Build and run your application to see that it looks and behaves the same way.