Reading at navigation documentation (<https://deve...
# compose
l
Reading at navigation documentation (https://developer.android.com/jetpack/compose/navigation#nav-with-args), I've seen that we can navigate with string argument. But is there a way to pass custom argument ? Or must I serialize/deserialize between my custom
class
and
String
? Or is even this last very bad practice ?
l
We just convert object to json and wrap to base64, i guess itโ€™s only way
๐Ÿ˜ณ 1
l
Thank you ๐Ÿ™‚ I am also thinking about handling the data directly in the main activity, where I define the
@Composable
: so to do state hoisting. I think i can handle that way also.
c
It's a bad practice to pass anything but strings. You should think of it like a web address. You want to give an id in the web address, not the full object serialized into a string. From the docs:
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.
tldr. Just use identifiers. Bonus being you can retrieve stuff after process death. if you really want to "share" an object, just put the object in some shared scope by the two things that need it.
โ˜๏ธ 1
๐Ÿ‘๐Ÿพ 1
i
Yep, identifiers make sense. Arguments shouldn't be the source of truth for data
๐Ÿคฉ 1
๐Ÿ‘๐Ÿพ 1
That being said, Navigation supports passing custom types if your identifier is complicated (you absolutely shouldn't be base64ing anything) : https://developer.android.com/guide/navigation/navigation-kotlin-dsl#custom-types
โž• 2
l
@Colton Idle Thank you. I was not aware of this fact. In fact I need to pass a list of PGNGame, which is a custom type itself.
@Ian Lake Thank you. So I'll need to review Jetpack Compose concepts : as I'm still having some issue understanding the fact that argument should not be the source of truth for data. Also my PGNGame custom data is quite a rather complex data : hold a mutable map from String to String and a list of another custom data.
@Colton Idle I will also investigate into the sharing solution, from the top
Composable
in main activity
As my shared data is very very complex (with a recursive data), I went into sharing it with a view model. Not sure if this is fine. Also I'm afraid this could create Memory Leak
Is there a better way to share complex recursive data among NavHost components ?
c
I think its fine. yeah. lol.
๐Ÿ‘๐Ÿพ 1
you just gotta make sure you can get that data back if it goes away (process death)
l
No other way => so I'm gonna for it
๐Ÿ‘ 1
I'm sure I can always recover data : as in fact it is made from a Chess Pgn file format (either from assets, or from local files). So all I have to do is to parse the file again, and it's quite fast (using an ANTLR4 grammar). So yes, data can be easily recovered.
Finally came to make my custom data
@Parcelize
and to use this feature
Copy code
val games = extractGames(fileData = it, context = context)
     navController.currentBackStackEntry?.savedStateHandle?.set(
       NavHostParcelizeArgs.gamesList,
       games
     )
navController.navigate(NavHostRoutes.gamePage)
and
Copy code
val gamesList =
        navController.previousBackStackEntry?.savedStateHandle?.get<List<PGNGame>>(
            NavHostParcelizeArgs.gamesList
        )
and
Copy code
@Composable
fun MainContent(stockfishLib: StockfishLib) {
    val navController = rememberNavController()
    NavHost(navController, startDestination = NavHostRoutes.gamesListPage) {
        composable(NavHostRoutes.gamesListPage) {
            GamesListPage(
                navController = navController,
            )
        }
        composable(NavHostRoutes.gamePage) {
                GamePage(
                    navController = navController,
                    stockfishLib = stockfishLib,
                )
        }
    }
}
This way should be far cleaner.
i
No, you really, really don't want to be abusing savedStateHandle for that. This is way, way worse than your initial code of having a
rememberSaveable
above the NavHost layer acting as a "repository" that both destinations use as their source of truth
๐Ÿ‘๐Ÿพ 1
I'd suggest reading the Guide to App Architecture, which talks specifically about how to get data onto your screens: https://developer.android.com/jetpack/guide
๐Ÿ‘ 1
๐Ÿ‘๐Ÿพ 1
l
Hi eveyone ! I've started to design my app with Jetpack Architecture components. But then I'm stuck about how to use my UseCase so that all screens can make a call to it. More in the following posts
This is the use case.
This is the data source.
This is the repository.
But how to "share" the use case to all screens ? I mean, where should I instantiate it ? In the
@composable
which defines the
NavHost
? And how to pass it to all screens ? In short, where should I create the single instance of
GamesFromFileExtractorUseCase
? Otherwise, should the
GamesFromFileExtractorUseCase
be a Singleton / object class ?
This is the current state of my main activity.
j
I wouldn't use a
object
+
lateinit var
if I could use a
class
+
@Singleton
+
val
๐Ÿ‘๐Ÿพ 1
l
Thank you. Could you give a simple snippet as an example ? Because I don't see yet how to apply your suggestion
Oups. Didn't realize that
@Singleton
is also a Dagger annotation. Thank you very much ๐Ÿ™‚
Meanwhile, it seems that using
@Singleton
does not make it a Singleton : https://stackoverflow.com/a/44237507/662618
So maybe I should create it inside Application class instead : https://stackoverflow.com/a/57118576/662618
j
depending on how you configure
@Singleton
, you should get the same instance always which is your use case
๐Ÿ‘๐Ÿพ 1
l
Thank you. So I'll try this way. Also the SO link I gave above was posted on 2019.
Here I'm calling
Copy code
(context.applicationContext as MyApplication).gamesFromFileExtractorUseCase.extractGame()
but I'm wondering whether it is better or worse than setting it inside NavHost state.