When I navigate to that screen I get this error, but the price type is Float. Can someone help me with this problem please?
data class Product(
val imgUrl: String = "",
val title: String = "",
val price: Float = 0f,
val description: String = "",
)
composable(
route = Screen.InspectProduct.route + "/{description}/{title}/{price}/{imgUrl}",
arguments = listOf(
navArgument(name = "title") { NavType.StringType },
navArgument(name = "description") { NavType.StringType },
navArgument(name = "price") { NavType.FloatType },
navArgument(name = "imgUrl") { NavType.StringType },
)
) { backStackEntry ->
Log.d(TAG, backStackEntry.arguments?.getFloat( "price")!!.toString())
InspectProduct1(
navController = navController,
Product(
title = backStackEntry.arguments?.getString("title")!!,
description = backStackEntry.arguments?.getString("description")!!,
imgUrl = backStackEntry.arguments?.getString("imgUrl")!!,
price = backStackEntry.arguments?.getFloat( "price")!!
)
)
}
navController.navigate(
route = Screen.InspectProduct.route + "/${product.description}/${product.title}/${product.price}/${urlEncoder(product.imgUrl)}"
)
2021-09-03 01:13:56.208 10933-10933/com.example.shop D/ContentValues: 0.0
2021-09-03 01:13:56.209 10933-10933/com.example.shop W/Bundle: Key price expected Float but value was a java.lang.String. The default value 0.0 was returned.
2021-09-03 01:13:56.209 10933-10933/com.example.shop W/Bundle: Attempt to cast generated internal exception:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Float
at android.os.BaseBundle.getFloat(BaseBundle.java:1145)
at android.os.Bundle.getFloat(Bundle.java:891)
at android.os.BaseBundle.getFloat(BaseBundle.java:1127)
at android.os.Bundle.getFloat(Bundle.java:878)
at com.example.shop.util.NavigationKt$Navigation$1$9.invoke(Navigation.kt:48)
at com.example.shop.util.NavigationKt$Navigation$1$9.invoke(Navigation.kt:38)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.navigation.compose.NavHostKt$NavHost$3$1.invoke(NavHost.kt:142)
at androidx.navigation.compose.NavHostKt$NavHost$3$1.invoke(NavHost.kt:141)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:215)
at androidx.compose.runtime.saveable.SaveableStateHolderImpl.SaveableStateProvider(SaveableStateHolder.kt:84)
at androidx.navigation.compose.NavBackStackEntryProviderKt.SaveableStateProvider(NavBackStackEntryProvider.kt:59)
at androidx.navigation.compose.NavBackStackEntryProviderKt.access$SaveableStateProvider(NavBackStackEntryProvider.kt:1)
at androidx.navigation.compose.NavBackStackEntryProviderKt$LocalOwnersProvider$1.invoke(NavBackStackEntryProvider.kt:51)
at androidx.navigation.compose.NavBackStackEntryProviderKt$LocalOwnersProvider$1.invoke(NavBackStackEntryProvider.kt:50)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:215)
at androidx.navigation.compose.NavBackStackEntryProviderKt.LocalOwnersProvider(NavBackStackEntryProvider.kt:46)
at androidx.navigation.compose.NavHostKt$NavHost$3.invoke(NavHost.kt:141)
at androidx.navigation.compose.NavHostKt$NavHost$3.invoke(NavHost.kt:134)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
at androidx.compose.runtime.internal.ComposableLambdaImpl$invoke$1.invoke(ComposableLambda.jvm.kt:127)
at androidx.compose.runtime.internal.ComposableLambdaImpl$invoke$1.invoke(ComposableLambda.jvm.kt:127)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:140)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2156)
at androidx.compose.runtime.ComposerImpl.skipToGroupEnd(Composer.kt:2422)
at androidx.compose.animation.CrossfadeKt$Crossfade$1$1.invoke(Crossfade.kt:75)
at androidx.compose.animation.CrossfadeKt$Crossfade$1$1.invoke(Crossfade.kt:69)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.animation.CrossfadeKt.Crossfade(Crossfade.kt:86)
at androidx.navigation.compose.NavHostKt.NavHost(NavHost.kt:134)
at androidx.navigation.compose.NavHostKt$NavHost$4.invoke(Unknown Source:13)
at androidx.navigation.compose.NavHostKt$NavHost$4.invoke(Unknown Source:10)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:140)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2156)
at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2399)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:2580)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:2573)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(SnapshotState.kt:540)
at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:2566)
2021-09-03 01:13:56.209 10933-10933/com.example.shop W/Bundle: at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:2542)
at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:613)
at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:764)
at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:103)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:447)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:416)
at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34)
at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109)
at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41)
at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:970)
at android.view.Choreographer.doCallbacks(Choreographer.java:796)
at android.view.Choreographer.doFrame(Choreographer.java:727)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
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)
First of all, I would like to say that you are not using the navigation exactly as it is intended.
If the number of fields in your object grows, will you add new parameters to the route? That doesn't seem convenient or reliable.
As per the Navigation documentation:
Caution: Passing complex data structures over arguments is considered an anti-pattern. Each destination should be responsible for loading UI data based on the minimum necessary information, such as item IDs. This simplifies process recreation and avoids potential data inconsistencies.
Instead, you could pass the object's id and pull it from a repository. You can see this in compose samples made by the maintainers. This is navigation destination where id is taken from the arguments, and this is the screen which takes an object from the repository by id.
The above does not invalidate the fact that the behavior you encountered looks like a bug, so I suggest you report it to the compose issue tracker.
In the meantime, you can switch to passing a string and converting it to float:
composable(
route = Screen.InspectProduct.route + "/{description}/{title}/{price}/{imgUrl}",
arguments = listOf(
navArgument(name = "title") { NavType.StringType },
navArgument(name = "description") { NavType.StringType },
navArgument(name = "price") { NavType.StringType },
navArgument(name = "imgUrl") { NavType.StringType },
)
) { backStackEntry ->
val product = Product(
title = backStackEntry.arguments?.getString("title")!!,
description = backStackEntry.arguments?.getString("description")!!,
imgUrl = backStackEntry.arguments?.getString("imgUrl")!!,
price = backStackEntry.arguments?.getString("price")!!.toFloat()
).toString()
}