androidkotlinandroid-jetpack-composekotlin-reified-type-parameters

This function has a reified type parameter and thus can only be inlined at compilation time, not called directly


I have the below code that compiles, but runtime crash

@Composable
fun Launcher() {
    val context = LocalContext.current
    LazyColumn(modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally) {
        item {
            context.StartActivityButton<LaunchedEffectActivity>()
        }
    }
}

@Composable
private inline fun <reified T : Activity>Context.StartActivityButton() {
    Button(onClick = {
        startActivity(Intent(this, T::class.java))
    }) {
        Text(T::class.toString())
    }
}

The error is

     Caused by: java.lang.UnsupportedOperationException: This function has a reified type parameter and thus can only be inlined at compilation time, not called directly.
        at kotlin.jvm.internal.Intrinsics.throwUndefinedForReified(Intrinsics.java:207)
        at kotlin.jvm.internal.Intrinsics.throwUndefinedForReified(Intrinsics.java:201)
        at kotlin.jvm.internal.Intrinsics.needClassReification(Intrinsics.java:219)
        at com.example.composesideeffects.ComposableSingletons$MainActivityKt.<clinit>(MainActivity.kt:52)
        at com.example.composesideeffects.MainActivity.onCreate(MainActivity.kt:25) 
        at android.app.Activity.performCreate(Activity.java:7994) 
        at android.app.Activity.performCreate(Activity.java:7978) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 

I have already used inline for my reified. What did I miss?


Solution

  • This seems like a bug, I suggest you report it.


    Inlining the action works fine:

    private inline fun <reified T : Activity> Context.startActivity() {
        startActivity(Intent(this, T::class.java))
    }
    // ..
    Button(onClick = {
        context.startActivity<MainActivity>()
    }) {
    
    }
    

    Creating composable function as an extension on Context seems very strange to me: you can get LocalContext.current in any composable.

    Here's how you can do the same without inlining:

    @Composable
    private fun StartActivityButton(activityClass: Class<*>) {
        val context = LocalContext.current
        Button(onClick = {
            context.startActivity(Intent(context, activityClass))
        }) {
        }
    }
    

    Usage:

    StartActivityButton(LaunchedEffectActivity::class.java)