I am converting an app that is a few years old to Jetpack Compose. It's fragment based, and all of the fragments are migrated to Compose already, but I hit a problem converting the one and only Activity
to use Compose. It should just be a simple Scaffold with a NavHost to receive the fragments, but it doesn't even complete onCreate
with a dummy Compose layout either.
class FrameActivity : AppCompatActivity(), KoinComponent {
lateinit var navController: NavHostController
private val viewModel: MainNavigationViewModel by viewModel()
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? =
ComposeView(context)
It is exploding while setting some transition view that I don't recall ever specifying anywhere or ever asking for. I can't tell what exactly is triggering this exception as there are no elements in my app in the stacktrace. I don't want to use whatever screen_simple.xml
is.
Caused by: android.view.InflateException: Binary XML file line #29 in android:layout/screen_simple: Cannot add views to ComposeView; only Compose content is supported
Caused by: java.lang.UnsupportedOperationException: Cannot add views to ComposeView; only Compose content is supported
at androidx.compose.ui.platform.AbstractComposeView.checkAddView(ComposeView.android.kt:201)
at androidx.compose.ui.platform.AbstractComposeView.addView(ComposeView.android.kt:376)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1139)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1096)
at android.view.LayoutInflater.inflate(LayoutInflater.java:694)
at android.view.LayoutInflater.inflate(LayoutInflater.java:538)
at android.view.LayoutInflater.inflate(LayoutInflater.java:485)
at com.android.internal.policy.DecorView.onResourcesLoaded(DecorView.java:2207)
at com.android.internal.policy.PhoneWindow.generateLayout(PhoneWindow.java:2709)
at com.android.internal.policy.PhoneWindow.installDecor(PhoneWindow.java:2772)
at com.android.internal.policy.PhoneWindow.getDecorView(PhoneWindow.java:2154)
at android.app.ActivityTransitionState.setEnterActivityOptions(ActivityTransitionState.java:174)
at android.app.Activity.performCreate(Activity.java:8605)
at android.app.Activity.performCreate(Activity.java:8573)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1456)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3764)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
The next place to look would be the Manifest, and I tried to set the theme
to various NoActionBar
variants to try and stop whatever is causing the animation transition to happen. I even tried omitting the theme element from here altogether.
<application
android:allowBackup="true"
...
android:theme="@style/Theme.Material3.Light.NoActionBar">
<activity
android:name=".activity.FrameActivity"
android:exported="true"
android:theme="@style/Theme.Material3.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I also tried to replace AppCompatActivity
with ComponentActivity
but this still produced the same exception.
class FrameActivity : ComponentActivity(), KoinComponent {
And then finally I tried sneaking in overridePendingTransition()
to onCreate()
but this didn't change the exception either. I can't seem to get rid of the exception and I don't want to be stuck with a part of the app missing the MaterialTheme
being used everywhere else.
Calling Compose from an Activity
should be as simple as this:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
MyApplicationTheme {
Surface {
MainScreen()
}
}
}
}
}
@Composable
fun MainScreen(
viewModel: MainNavigationViewModel = viewModel()
) {
val navController = rememberNavController()
Scaffold(
topBar = {
CenterAlignedTopAppBar(title = { Text("My Application") })
}
) { padding ->
NavHost(
navController = navController,
startDestination = "screenA",
modifier = Modifier.padding(padding)
) {
composable("screenA") { /** Your AndroidFragment or Composable **/ }
composable("screenB") { /** Your AndroidFragment or Composable **/ }
}
}
}
In order to obtain a MyApplicationTheme
, head over to the Material3 Theme Builder and enter the main colors of your current themes.xml
there. Then you can export a Theme.kt
file that is compatible with Compose.
Also ensure all dependencies are present as described in the Compose Migration Codelab.