android – Why do I get error when using rememberLauncherForActivityResult on my GalaxyWatch4 but not on my Emulator?

I have a wear composable ap that is running well in my emulator. When I launch it on my Galaxy Watch 4 I receive the following error when opening the composable containing the rememberLauncherForActivityResult:

2022-06-17 10:15:26.877 20559-20559/com.my.app E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.my.app, PID: 20559
    java.lang.IllegalArgumentException: Failed requirement.
        at androidx.compose.runtime.saveable.ListSaverKt$listSaver$1.invoke(ListSaver.kt:39)
        at androidx.compose.runtime.saveable.ListSaverKt$listSaver$1.invoke(ListSaver.kt:33)
        at androidx.compose.runtime.saveable.SaverKt$Saver$1.save(Saver.kt:66)
        at androidx.lifecycle.viewmodel.compose.SavedStateHandleSaverKt$saveable$1.saveState(SavedStateHandleSaver.kt:65)
        at androidx.lifecycle.SavedStateHandle.savedStateProvider$lambda-0(SavedStateHandle.kt:60)
        at androidx.lifecycle.SavedStateHandle.$r8$lambda$85q68529u9GpNelrug3JBSyWf4c(Unknown Source:0)
        at androidx.lifecycle.SavedStateHandle$$ExternalSyntheticLambda0.saveState(Unknown Source:2)
        at androidx.lifecycle.SavedStateHandlesProvider.saveState(SavedStateHandleSupport.kt:147)
        at androidx.savedstate.SavedStateRegistry.performSave(SavedStateRegistry.kt:247)
        at androidx.savedstate.SavedStateRegistryController.performSave(SavedStateRegistryController.kt:81)
        at androidx.navigation.NavBackStackEntry.saveState(NavBackStackEntry.kt:236)
        at androidx.navigation.NavBackStackEntryState.<init>(NavBackStackEntryState.kt:37)
        at androidx.navigation.NavController.saveState(NavController.kt:2032)
        at androidx.navigation.compose.NavHostControllerKt$NavControllerSaver$1.invoke(NavHostController.kt:81)
        at androidx.navigation.compose.NavHostControllerKt$NavControllerSaver$1.invoke(NavHostController.kt:80)
        at androidx.compose.runtime.saveable.SaverKt$Saver$1.save(Saver.kt:66)
        at androidx.compose.runtime.saveable.RememberSaveableKt$rememberSaveable$1$valueProvider$1.invoke(RememberSaveable.kt:102)
        at androidx.compose.runtime.saveable.SaveableStateRegistryImpl.performSave(SaveableStateRegistry.kt:136)
        at androidx.compose.ui.platform.DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$registered$1.saveState(DisposableSaveableStateRegistry.android.kt:83)
        at androidx.savedstate.SavedStateRegistry.performSave(SavedStateRegistry.kt:247)
        at androidx.savedstate.SavedStateRegistryController.performSave(SavedStateRegistryController.kt:81)
        at androidx.activity.ComponentActivity.onSaveInstanceState(ComponentActivity.java:368)
        at android.app.Activity.performSaveInstanceState(Activity.java:2166)
        at android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1488)
        at android.app.ActivityThread.callActivityOnSaveInstanceState(ActivityThread.java:5517)
        at android.app.ActivityThread.callActivityOnStop(ActivityThread.java:4900)
        at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:4865)
        at android.app.ActivityThread.handleStopActivity(ActivityThread.java:4939)
        at android.app.servertransaction.StopActivityItem.execute(StopActivityItem.java:40)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2073)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:246)
        at android.app.ActivityThread.main(ActivityThread.java:7690)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)

The ListSaverKt where require(canBeSaved(item)) seems to be an issue:

fun <Original, Saveable> listSaver(
    save: SaverScope.(value: Original) -> List<Saveable>,
    restore: (list: List<Saveable>) -> Original?
): Saver<Original, Any> = @Suppress("UNCHECKED_CAST") Saver(
    save = {
        val list = save(it)
        for (index in list.indices) {
            val item = list[index]
            if (item != null) {
                require(canBeSaved(item))
            }
        }
        if (list.isNotEmpty()) ArrayList(list) else null
    },
    restore = restore as (Any) -> Original?
)

The Composable I use:

@Composable
fun MyTextInputButton(
    btn_description: String,
    default_value:String = "",
    choices: Array<String> = arrayOf("Choice 1", "Choice 2", "Choice 3"),
    color: ChipColors = ChipDefaults.primaryChipColors(),
    onValueChange: (String) -> Unit)
{
    var textForUserInput by remember { mutableStateOf(default_value) }
    val launcher =
        rememberLauncherForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ) {
            it.data?.let { data ->
                val results: Bundle = RemoteInput.getResultsFromIntent(data)
                val newInputText: CharSequence? = results.getCharSequence(btn_description)
                textForUserInput = newInputText.toString()
                run { onValueChange(textForUserInput) }
            }
        }
    val intent: Intent = RemoteInputIntentHelper.createActionRemoteInputIntent()
    val remoteInputs: List<RemoteInput> = listOf(
        RemoteInput.Builder(btn_description)
            .setLabel("INPUT LABEL")
            .setChoices(choices)
            .wearableExtender {
                setEmojisAllowed(false)
                setInputActionType(EditorInfo.IME_ACTION_DONE)
            }.build()
    )

    RemoteInputIntentHelper.putRemoteInputsExtra(intent, remoteInputs)


    Chip(
        onClick = {
            launcher.launch(intent)
        },
        label = {
            Text(
                btn_description,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis
            )
        },
        secondaryLabel = {
            Text(
                text = textForUserInput,
            )
        },
        modifier = Modifier.fillMaxWidth(),
        colors = color
    )
}

Leave a Comment