Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash when using Parcelable class as navigation argument #653

Closed
SkashEU opened this issue Jun 19, 2024 · 6 comments
Closed

Crash when using Parcelable class as navigation argument #653

SkashEU opened this issue Jun 19, 2024 · 6 comments

Comments

@SkashEU
Copy link

SkashEU commented Jun 19, 2024

I'm experiencing a crash when using the Android Parcelable class as a navigation argument in the library. It seems that the generated NavType class code has a bug. Specifically, the function parseValue is called twice: once with the correct value and once with the key as the value, which leads to the crash.

Im using the version: 2.1.0-beta09

Steps to Reproduce:

  1. Define a Parcelable class to be used as a navigation argument.
  2. Use the Parcelable class as a navigation argument in the library.
  3. Observe the crash during navigation.

Expected Behavior:

The navigation should succeed without any crashes, with the parseValue function being called correctly with the intended value.

Actual Behavior:

The parseValue function is called twice:

  1. The first call is with the correct value.
  2. The second call is with the key as the value, causing the crash.
@raamcosta
Copy link
Owner

Hi 👋

This is definitively not an issue general to parcelable nav arguments given that I have plenty of working examples with them.

Can you share more about how the class looks like and how you are navigating?
As a side note, the function “parseValue” is not called by us, official library is orchestrating that.

@raamcosta
Copy link
Owner

Also, add the crash stacktrace if possible 🙏

@SkashEU
Copy link
Author

SkashEU commented Jun 19, 2024

Hey, thanks for the fast reply!

Alright, thanks for the info. That's good to know. Ye I tried it with multiple different classes but I can surely share an example.

@Parcelize
    actual class Filter actual constructor(
        val selectedFilterTagIds: List<Int>
    ) : Parcelable

That's my target composable

@Destination<RecipeCategoryGraph>(
   start = true,
   visibility = CodeGenVisibility.INTERNAL
)
@Composable
internal fun RecipeCategoryScreen(
   filter: Filter,
   navigator: DestinationsNavigator,
   viewModel: RecipeCategoryViewModel = viewModel { RecipeCategoryViewModel(filter) }
)

That's my navigate call

    RecipeCategoryNavGraph(
                        navArgs = RecipeCategoryScreenDestinationNavArgs(
                            Filter(result.value.selectedTagIds)
                        )
                    )

@SkashEU
Copy link
Author

SkashEU commented Jun 19, 2024

Also, add the crash stacktrace if possible 🙏

Ye, sure:

java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
    at java.util.Collections$SingletonList.get(Collections.java:5042)
    at com.ramcosta.composedestinations.navargs.parcelable.DefaultParcelableNavTypeSerializer.fromRouteString(DefaultParcelableNavTypeSerializer.kt:28)
    at com.ramcosta.composedestinations.navargs.parcelable.DefaultParcelableNavTypeSerializer.fromRouteString(DefaultParcelableNavTypeSerializer.kt:19)
    at com.ramcosta.composedestinations.generated.recipecategory.navtype.RecipeSearchTypeNavType.parseValue(RecipeSearchTypeNavType.kt:33)
    at com.ramcosta.composedestinations.generated.recipecategory.navtype.RecipeSearchTypeNavType.parseValue(RecipeSearchTypeNavType.kt:16)
    at androidx.navigation.NavType.parseAndPut(NavType.kt:95)
    at androidx.navigation.NavDeepLink.parseArgument(NavDeepLink.kt:361)
    at androidx.navigation.NavDeepLink.getMatchingPathArguments(NavDeepLink.kt:261)
    at androidx.navigation.NavDeepLink.getMatchingArguments(NavDeepLink.kt:194)
    at androidx.navigation.NavDestination.matchDeepLink(NavDestination.kt:403)
    at androidx.navigation.NavDestination.matchDeepLink(NavDestination.kt:381)
    at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.kt:88)
    at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.kt:59)
    at androidx.navigation.NavController.navigateInternal(NavController.kt:271)
    at androidx.navigation.NavController.navigate(NavController.kt:2040)
    at androidx.navigation.NavController.navigate(NavController.kt:1973)
    at androidx.navigation.NavController.navigate(NavController.kt:2400)
    at com.ramcosta.composedestinations.navigation.DestinationsNavController.navigate(DestinationsNavController.kt:33)
    at com.ramcosta.composedestinations.navigation.DestinationsNavigator$DefaultImpls.navigate$default(DestinationsNavigator.kt:52)
    at com.example.RecipesScreenKt$RecipesScreen$1$1.invoke(RecipesScreen.kt:53)
    at com.example.RecipesScreenKt$RecipesScreen$1$1.invoke(RecipesScreen.kt:49)
    at com.ramcosta.composedestinations.result.ResultRecipientImpl.handleResultIfPresent(ResultRecipientImpl.kt:66)
    at com.ramcosta.composedestinations.result.ResultRecipientImpl.access$handleResultIfPresent(ResultRecipientImpl.kt:17)
    at com.ramcosta.composedestinations.result.ResultRecipientImpl$onNavResult$1$observer$1.onStateChanged(ResultRecipientImpl.kt:36)
    at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.jvm.kt:320)
    at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.jvm.kt:198)
    at com.ramcosta.composedestinations.result.ResultRecipientImpl.onNavResult$lambda$2(ResultRecipientImpl.kt:48)
    at com.ramcosta.composedestinations.result.ResultRecipientImpl.$r8$lambda$QiPsutwrk8k00_u_HUuef2cXYxg(Unknown Source:0)
    at com.ramcosta.composedestinations.result.ResultRecipientImpl$$ExternalSyntheticLambda0.invoke(Unknown Source:6)
    at androidx.compose.runtime.DisposableEffectImpl.onRemembered(Effects.kt:83)
    at androidx.compose.runtime.CompositionImpl$RememberEventDispatcher.dispatchRememberObservers(Composition.kt:1364)
    at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:992)
    at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:1013)
    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:678)
    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:578)
    at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:41)
    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:1397)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1408)
    at android.view.Choreographer.doCallbacks(Choreographer.java:1008)
    at android.view.Choreographer.doFrame(Choreographer.java:934)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1382)
    at android.os.Handler.handleCallback(Handler.java:959)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loopOnce(Looper.java:232)
    at android.os.Looper.loop(Looper.java:317)
    at android.app.ActivityThread.main(ActivityThread.java:8501)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:878)

@raamcosta
Copy link
Owner

I was able to reproduce it, still looking into it.

One thing that could be an ok workaround is to navigate to the start destination directly rather than to the nav graph.

@raamcosta
Copy link
Owner

Fixed, this was a change that happened on the official library which I didn't know about and it changed a behaviour here where it could call parseValue with the default value (like {argName}).

Next release this will be fixed, but please let me know either way how it goes! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants