Jetpack Compose with Android Fragment: A Fun and Dynamic Duo!

Ah, Jetpack Compose — the shiny new tool in our Android arsenal. It promises simplicity, elegance, and speed for building UIs. But what happens when you want to use it in an app still tethered to our good old friend, the Fragment? Fear not! You can have the best of both worlds. Let’s dive in and make this duo work, with a sprinkle of fun.
Why Mix Compose with Fragments?
Sure, Jetpack Compose is the future, but:
- Your project is legacy-heavy and built around Fragments.
- You want to migrate gradually, instead of throwing everything into chaos.
- Some features, like Navigation or libraries, are still Fragment-friendly.
Whatever your reason, integrating Compose into a Fragment-based app can be seamless and… dare I say, fun?
Setting Up the Scene
Before we dive into code, ensure you’ve set up Jetpack Compose in your project:
Add dependencies:
implementation "androidx.activity:activity-compose:1.7.2" implementation "androidx.compose.ui:ui:1.4.3" implementation "androidx.compose.material:material:1.4.3" implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1"
Enable Compose in your build.gradle:
android {
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.5.3'
}
.
.
.
}
With this, we’re ready to rock and roll.
Jetpack Compose Inside a Fragment
Imagine this: You have a MyFragment where you want to sprinkle some Compose magic. Here’s how you do it:
1. Create a ComposeView
The magic starts with a ComposeView. It’s a bridge that connects the world of XML to Compose. In your Fragment, override onCreateView:
class MyFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val composeView = ComposeView(requireContext())
composeView.setContent {
GreetingMessage("Hello from Compose inside Fragment!")
}
return composeView
}
.
.
.
}
2. Define Your Compose Content
Compose UIs are just functions. Here’s a simple composable:
@Composable
fun GreetingMessage(message: String) {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFFBB86FC)),
contentAlignment = Alignment.Center
) {
Text(
text = message,
color = Color.White,
fontSize = 24.sp,
fontWeight = FontWeight.Bold
)
}
}
And there you go! You’ve successfully placed a Compose UI inside a Fragment.
Android Fragment Inside Jetpack Compose
What if the tables are turned? You want to embed a Fragment within Jetpack Compose. You can do that too, using the AndroidView or Android ViewBinding composable.
Its required Android ViewBinding on Fragments. See full details here about view binding https://developer.android.com/topic/libraries/view-binding.
After enable generate build to generate the view binding class then follow the following steps.
1. Create following xml in layout directory.
my_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/my_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.hello.world.lib.ui.HelloFragment"
/>
2. Use Fragment Inside Compose
@Composable
fun GreetingMessage(message: String) {
AndroidViewBinding(
MyFragmentBinding::inflate,
Modifier.fillMaxSize(),
) {
val helloFrag = this.myFragment.getFragment<HelloFragment>()
// helloFrag.binding access all public fun and variable.
}
}
Here we go another approach…
1. Add a FragmentContainerView
In your Compose layout, use AndroidView to embed a FragmentContainerView:
@Composable
fun FragmentContainer() {
AndroidView(
factory = { context ->
FragmentContainerView(context).apply {
id = R.id.fragment_container_view
}
},
modifier = Modifier.fillMaxSize()
)
}
2. Attach the Fragment
In your Activity or Parent Fragment:
setContent {
FragmentContainer()
}
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container_view, MyFragment())
.commit()
Communicating Between Compose and Fragment via ViewModel
A ViewModel is your best friend for seamless communication between Compose and Fragments. The `activityViewModels` is key to transfer data between the fragments to Composable components.
Another option we can use hilt dependency injection to inject singleton class or create companion object to fragment and use the same in Composable to share static data.
1. Create a Shared ViewModel
class SharedViewModel : ViewModel() {
val message: MutableLiveData<String> = MutableLiveData("Hello from ViewModel!")
}
2. Observe ViewModel in Fragment
class MyFragment : Fragment() {
private val viewModel: SharedViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val composeView = ComposeView(requireContext())
composeView.setContent {
GreetingWithViewModel(viewModel)
}
return composeView
}
}
3. Use ViewModel in Compose
@Composable
fun GreetingWithViewModel(viewModel: SharedViewModel) {
val message by viewModel.message.observeAsState()
Box(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFFBB86FC)),
contentAlignment = Alignment.Center
) {
Text(
text = message ?: "",
color = Color.White,
fontSize = 24.sp,
fontWeight = FontWeight.Bold
)
}
}
}
This approach ensures both your Fragment and Compose UI stay in sync, fostering a harmonious relationship between the two.
Boom! XML and Compose working together like peanut butter and jelly. 🍓🍪
GIF Time! Picture this: Compose and Fragments awkwardly working together for the first time.

But after some code love, they become best friends:
Tips for a Happy Integration Folks
State Management: Use ViewModel to manage state and pass data to Compose. This avoids tight coupling and ensures reusability.
class MyViewModel : ViewModel() {
val message = MutableLiveData("Hello from ViewModel!")
}
In Compose:
@Composable
fun GreetingMessage(viewModel: MyViewModel) {
val message by viewModel.message.observeAsState()
Text(text = message ?: "")
}
Animation Fun: Add some Compose animations for a touch of pizzazz ;).
@Composable
fun AnimatedGreetingMessage() {
var isBig by remember { mutableStateOf(false) }
val size by animateDpAsState(targetValue = if (isBig) 200.dp else 100.dp)
Box(
modifier = Modifier
.size(size)
.background(Color.Red)
.clickable { isBig = !isBig }
)
}
Imagine this box growing and shrinking. Fun, right?
Problem we face with Android Fragment & Compose
Yeahhhhh, Apart from fun its give us little struggles we solved with workaround but still its fun :P.
Problem 1:
When we use a Fragment inside the Jetpack Compose navigation component while switching between Compose view and a fragment some fragment lifecycle gets messed up and the fragment not refreshing probably.
So we come with with workaround show loading or animation on 100 mils.
@Composable
fun HelloGreetingMessage() {
var show by remember { mutableStateOf(false) }
LaunchedEffect(key1 = state.value.uiState) {
show = false
delay(100)
show = true
}
if (show) {
AndroidViewBinding(
MapFragmentBinding::inflate,
Modifier.fillMaxSize(),
) {}
}
}
This will solve the issue for time period it might not occur on latest Jetpack compose so test it and use it.
Problem 2:
Loading… 😉
If any new problem come it will listed here make sure bookmark this thread.
Zoom image will be displayed
Photo by Huma Kabakci on Unsplash
Job Offers
Conclusion
Jetpack Compose and Fragments may seem like an unlikely pair, but they can work harmoniously. Whether you’re gradually migrating or just experimenting, these steps make integration straightforward and enjoyable.
So, what are you waiting for? Go sprinkle some Compose magic in your Fragment-based app and share your experiences. And remember, a little humor (and maybe a GIF) makes coding even better! 😉
This article was previously published on proandroiddev.com.



