Android Jetpack Compose - How to passing data to NavHost start destination

33 Views Asked by At

I am currently working on a migration code from Java to Kotlin with Android Jetpack Compose

The use case is a QR Code has to be generated for coordinates data sent from the 1st screen to the QR Code display screen. I have to pass coordinate data via the Navigation graph from the previous screen to the next screen. The fetched data via the navigation graph will be used to generate a QR Code to share the coordinate data with others

I did go through several documentation that passing parameters to NavHost startdestination is not possible however I do not have any other option. Since this is a project code I cannot take the liberty to change the NAvHost configured and I have to achieve the navigation only with what is available.

Since this is the actual project code I have changed the names of the methods and composables. Hence please ignore the typos. Passing parameter data to startDestination is not passing the data in the AppNAvGraph -> composable.

I pass the data like this

  @AndroidEntryPoint
class QRCodeScreen(val location: Location) : BaseFragment() {
  
    private val appViewModel: AppViewModel by viewModels()

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        return ComposeView(requireContext()).apply {
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)

            setContent {
                val locationJson = location.toJson(true)
                MyApp(
                    viewModel = appViewModel, initialDestination = NavigationRoute.ShareQRCodeData,
                    initialDestinationParameters = arrayOf("locationJson" to locationJson.toString()),
                )
            }
        }
    }
}

// The Navigation graph should bring the passed parameter data to this composable.

@Composable
fun QRCodeScreen(
    qrCodeScreenViewModel: QRCodeScreenViewModel,
    location: Location?,
    modifier: Modifier = Modifier,
) {

// location object will be used from here onwards to generate a QR Code
    QRCodeScreen(
      
        modifier = modifier,

        )
}

MyApp

@Composable
fun MyApp(
    viewModel: MyAppViewModel,
    modifier: Modifier = Modifier,
    initialDestination: NavigationRoute = NavigationRoute.Map,
    vararg initialDestinationParameters: Pair<String, String?> = emptyArray(),
) {
   
    val navigationController = rememberNavController()

    var startDestination = initialDestination.route

    if (initialDestinationParameters.isNotEmpty()) {
        val parametersMap = initialDestinationParameters.toMap()
        val queryString = parametersMap.entries.joinToString("&") {
            "${it.key}=${it.value}"
        }
        startDestination = "${initialDestination.route}/$queryString"
        navigationController.navigate(startDestination)
    }


    MyAppTheme {
        BackHandler {
            navigationController.navigateUp()
        }
        CompositionLocalProvider(LocalWindowSizeClass provides windowSizeClass) {
            NavHost(
                modifier = modifier,
                navController = navigationController,
                startDestination = startDestination,
                enterTransition = { defaultEnterTransition },
                exitTransition = { defaultExitTransition },
                popEnterTransition = { defaultPopEnterTransition },
                popExitTransition = { defaultPopExitTransition },
            ) {
                AppNavGraph(navController = navigationController, appViewModel = viewModel)
            }
        }
    }
}

NavGraph

sealed class NavigationRoute(val route: String) {

       object ShareQRCodeData : NavigationRoute("ShareQRCodeData")
}

    fun NavGraphBuilder.AppNavGraph(navController: NavController, appViewModel: MyAppViewModel) {
       composable(
            route = "${NavigationRoute.ShareQRCodeData.route}/locationJson={locationJson}",
                arguments = listOf(
                navArgument("locationJson") {
                    type = NavType.StringType
                },
            ),
        ) { backStackEntry ->
// This is coming only as null or {} if I pass a default value.
            val locationJson = backStackEntry.arguments?.getString("locationJson")
            val location = Gson().fromJson(locationJson, RichLocation::class.java)
            val viewModel = hiltViewModel<ShareDestinationViewModel>()
            ShareDestinationScreen(shareDestinationViewModel = viewModel, location = location)
        }
    
    }

I did go through the methods provided in this link. https://developer.android.com/guide/navigation/use-graph/pass-data

but my project does not use any XML navigation graph and it is done programmatically. I could not apply that here.

Can any of you please show me some good ways? I am breaking my head for two days.

Edit: I am getting errors like this java.lang.IllegalArgumentException: Cannot navigate to NavDeepLinkRequest{ uri=android-app://androidx.navigation/ShareQRCodeData/locationJson={"location":{"coordinate":{"latitude":54.845,"longitude":7.20}},"title":"N 54.845° E 7.20°","description":"Coordinate","type":{"type":"coordinate"}} }. Navigation graph has not been set for NavController androidx.navigation.NavHostController@650fc28.

0

There are 0 best solutions below