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
)
}