Jetpack 使用 Kotlin DSL 组合导航传递自定义对象

问题描述 投票:0回答:1

我正在 Kotlin DSL 和 Navigation Compose 中尝试类型安全,但看起来它没有按预期工作,以下是我的代码:

屏幕:

@Serializable
data object SelectMenuNav

@Serializable
data class SelectProductNav(
    val menuSelection: MenuSelection
)

@Serializable
data class ProductDetailsNav(
    val menuSelection: MenuSelection,
    val product: Product
)

我想传递可组合的自定义对象

object CustomNavType {
    val ProductType = object : NavType<Product>(
        isNullableAllowed = false
    ) {
        override fun get(bundle: Bundle, key: String): Product? {
            return Json.decodeFromString(bundle.getString(key) ?: return null)
        }

        override fun parseValue(value: String): Product {
            return Json.decodeFromString(Uri.decode(value))
        }

        override fun put(bundle: Bundle, key: String, value: Product) {
            bundle.putString(key, Json.encodeToString(value))
        }

        override fun serializeAsValue(value: Product): String {
            return Uri.encode(Json.encodeToString(value))
        }
    }
}

我的应用导航

@Composable
fun AppNavigation(modifier: Modifier = Modifier) {
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = SelectMenuNav
    ) {
        composable<SelectMenuNav> {
            ChooseMenuScreen(onSelection = { menuSelection ->
                navController.navigate(
                    SelectProductNav(
                        menuSelection = menuSelection
                    )
                )
            })
        }
        composable<SelectProductNav>(
            typeMap = mapOf(
                typeOf<MenuSelection>() to NavType.EnumType(MenuSelection::class.java)
            )
        ) {
            val menuSelection = it.toRoute<SelectProductNav>().menuSelection
            ChooseProductScreen(
                menuSelection = menuSelection,
                viewModel = hiltViewModel(),
                onNavigateToProductDetails = { product ->
                    navController.navigate(
                      ProductDetailsNav(
                          product = product,
                          menuSelection = menuSelection
                      )
                    )
                })
        }
        composable<ProductDetailsNav>(
            typeMap = mapOf(
                typeOf<Product>() to CustomNavType.ProductType,
                typeOf<MenuSelection>() to NavType.EnumType(MenuSelection::class.java)
            )
        ) { backStackEntry ->
            Log.d("AppNavigation", "ProductDetailsNav: ${backStackEntry.toRoute<ProductDetailsNav>()}")
            ProductDetailsScreen(
                modifier = Modifier,
                vm = hiltViewModel(),
                navigateToEditor = {},
                navigateBack = {}
            )
        }
    }
}

尽管 Log 可以很好地显示已在可组合项之间成功传递的产品:

D  ProductDetailsNav: ProductDetailsNav(menuSelection=NAVA, product=Product(id=4371, productName=[...]

我的视图模型抛出错误:

  java.lang.IllegalArgumentException: Route app.xml.aionianew.navigation.ProductDetailsNav could not find any NavType for argument product of type app.xml.aionianew.database.internal.data.Product - typeMap received was {}
                                                                                                        at androidx.navigation.serialization.RouteSerializerKt$generateNavArguments$2$1.invoke(RouteSerializer.kt:108)
                                                                                                        at androidx.navigation.serialization.RouteSerializerKt$generateNavArguments$2$1.invoke(RouteSerializer.kt:103)
                                                                                                        at androidx.navigation.NamedNavArgumentKt.navArgument(NamedNavArgument.kt:21)
                                                                                                        at androidx.navigation.serialization.RouteSerializerKt.generateNavArguments(RouteSerializer.kt:103)
                                                                                                        at androidx.navigation.SavedStateHandleKt.internalToRoute(SavedStateHandle.kt:50)
                                                                                                        at app.xml.aionianew.screens.product_details.ViewModelProductDetails.<init>(ViewModelProductDetails.kt:1018)
                                                                                                        at app.xml.aionianew.DaggerMyApp_HiltComponents_SingletonC$ViewModelCImpl$SwitchingProvider.get(DaggerMyApp_HiltComponents_SingletonC.java:497)
                                                                                                        at dagger.hilt.android.internal.lifecycle.HiltViewModelFactory$2.createViewModel(HiltViewModelFactory.java:133)

我在视图模型中的代码如下:

@HiltViewModel
class ViewModelProductDetails @Inject constructor(
    private val uc: UseCasesProductDetails,
    savedState: SavedStateHandle
) : ViewModel() {

    private val selectedProduct: Product = savedState.toRoute<ProductDetailsNav>().product
    private val menuSelection:MenuSelection = savedState.toRoute<ProductDetailsNav>().menuSelection

所以问题是我错过了什么......

android android-jetpack-compose android-jetpack-navigation kotlin-dsl
1个回答
0
投票

savedState.toRoute
also 需要一个
typeMap
- 如果没有
typeMap
,它不知道如何将
SavedStateHandle
转换回你的对象,所以你会想要传递与你相同的
typeMap
在 ViewModel 的导航图定义中使用:

private val productDetails = savedState.toRoute<ProductDetailsNav>(
    typeMap = mapOf(
        typeOf<Product>() to CustomNavType.ProductType,
        typeOf<MenuSelection>() to NavType.EnumType(MenuSelection::class.java)
    )
)
private val selectedProduct: Product = productDetails.product
private val menuSelection: MenuSelection = productDetails.menuSelection
© www.soinside.com 2019 - 2024. All rights reserved.