1

I need to pass a Song object from HomePage to PlayerPage. Now I have already created a somewhat tolerable routing mechanism. Since I have both bottom navigation and full-screen pages in my application.

Right now I am facing an issue with passing objects through navigation. I have already referred to this and this guide. But cannot connect the dots between the answer and my existing navigation.

I have created a Router interface:

interface Router {
    fun openHome()
    fun openAlbumPage()
    fun openNotification()
    fun openSettings()
    fun openPlayer()
    fun openSearchPage()

    fun goBack()
    fun <T: Any> getArgs(tag: String): T?
}

and the implementation is as:

class RouterImpl (
    private val navHostController: NavHostController,
    private val startDestination: String = HOME
) : Router {
    override fun openHome() {
        navigate(Page.Home, removeFromHistory = true, singleTop = true)
    }
    .....
    override fun openPlayer() {
        navigate(Page.Player)
    }
    private fun navigate(
        page : Page,
        removeFromHistory : Boolean = false,
        singleTop: Boolean = false
    ){
        navHostController.apply {
            navigate(page.route){
                if(removeFromHistory){
                    if(singleTop){
                        popUpTo(Page.Home.route)
                    }else{
                        popUpTo(0){
                            saveState = false
                        }
                    }
                } else{
                    restoreState = true
                }
                launchSingleTop = singleTop
            }
        }
    }

    override fun goBack() {
        navHostController.apply {
            navigateUp()
            navigate(startDestination){
                launchSingleTop = true
                restoreState = true
            }
        }
    }

    private fun checkArgsAndNavigate(it: Any?, page: Page): () -> Unit = {
        it?.let {
            navHostController.putArgs(Pair(page.tag, it))
        }
        navigate(page)
    }

    @SuppressLint("LongLogTag")
    override fun <T: Any> getArgs(tag: String): T? {
        return try{
            navHostController.previousBackStackEntry?.arguments?.get(tag) as T?
        } catch (ex: Exception){
            Log.d("Exception from getArgs: ", ex.toString())
            null
        }
    }
}

I usually pass the router object to desired buttons and just call the associated method: router.openPlayerPage.

Inside my NavigationContainer:

fun NavigationContainer(
    router: Router,
    navController: NavHostController,
    paddingValues: PaddingValues
){
    val startDestination = remember { mutableStateOf(Page.Splash.route) }
    LaunchedEffect(startDestination){
        if(startDestination.value == Page.Home.route){
            router.openHome() 
        }
    }
    NavHost(
        navController = navController,
        startDestination = startDestination.value
    ){
        composable(Page.Splash.route){
            SplashPage(
                goBack = {
                    startDestination.value = Page.Home.route
                }
            )
        }
        /*
             Bottom Navigation Bar
        */
        composable(Page.Home.route){
            HomePage(router)
        }
        composable(Page.Favorite.route){
            FavoritePage()
        }
        composable(Page.Profile.route){
            ProfilePage()
        }
        /*
        =============================================
        */
 
        composable(Page.Player.route, Song song){ // unresolved reference: song
            PlayerPage(song = song)
        }
        composable(Page.Search.route){
            SearchPage()

        }
    }
}

I was thinking of sending the object to desired composable using bacStackEntry rather than converting it to json string and passing it as a string.

How can I solve this issue? thanks.

The full code is available here

zain ul din
  • 1
  • 1
  • 2
  • 23

1 Answers1

3

Use Gson, Just parse the object into JSON like this: Gson().toJson(myObj) and pass it as String and on the other screen parsed back to the object you want Gson().fromJson(json,Object::class.java)

Unes
  • 312
  • 7
  • 12