Reputation: 129
i have a data class
data class Holder(uri: String, title: String, desc: String, source: String, color: String?)
that i have from screen a, that i want to pass along to screen b. i have the code set up as follows:
@Composable
fun A(navigateToScreenB: (holder: Holder) -> Unit) {...}
@Composable
fun B(holder: Holder) {...}
in my nav file:
composable(
route = Screen.b.route
) {
B(how to get `Holder` to pass here)
}
composable(
route = Screen.A.route
) {
A(
navigateToScreenB = { it ->
// `it` is my data class `Holder`, but how to pass it to screen b?
navController.navigate(Screen.B.route)
}
)
}
any insight on this?
Upvotes: 3
Views: 2175
Reputation: 199805
tl/dr: you shouldn't be passing the object at all, the same way you don't see a website that is example.com/data/{the whole object in the URL}
, you'd see example.com/data/{a unique ID used to retrieve the object}
As per this thread, if the object exists only at the UI layer (i.e., it isn't coming from a remote database or any other source of truth), you can just pass the object directly by following the documentation and making your class Parcelable
and serializing it to include it as part of your Screen.b.route
just like any other argument.
However, you've said that your Holder
object actually comes from a remote database. That same thread goes on to discuss exactly this case:
A better way to start the conversation is figuring out how StoreList is going to recreate its list after process death and recreation. Your objects have been wiped from memory entirely, which means that ViewModel needs to be talking to the actual source of truth (i.e., your repository layer - note that doesn't mean "save to disk" or "database", it just means the layer responsible for getting your data)
Once you have a repository layer anyways (since a ViewModel shouldn't be doing network calls or disk access directly), that's also the layer that can do in memory caching
Keep in mind that every list already has a way to uniquely define each item by the index in the list
So at that point you already have everything you need - a repository both destinations can talk to that is the single source of truth for Store objects and an index into the list that you can pass to the details screen to define you element
And if you start persisting those objects into a database, the rest of the layers don't have to care
(of course, you probably will add a unique ID to each element if you do add it to a database at some point, which then makes the index based approach unnecessary)
So how you should actually be doing this is:
Create a data layer that is responsible for loading your data. No other layer should know that your data is actually from a remote database. Okhttp caching is a simple way to add caching to prevent redownloading data in a way that is transparent to the other layers.
Both Screen A and Screen B would talk to the same data layer, generally, as per the UI Layer documentation, would be by using a state holder such as a ViewModel
that is responsible for loading data from the data layer.
2a) Screen A would request the entire list of Holder
objects from the data layer, which would load the entire list from the remote database.
2b) Screen B would request just a single Holder
object, either by using the index in the list or a unique key if one is available (it isn't clear from your Holder
class if a unique key exists)
Instead of passing the entire Holder
as part of Screen B's route argument, you'd pass only that unique key, which could simply be the index in the list or something more complicated if your remote database has such a unique key (note that a Uri
would need to be encoded via Uri.encode
if included in a route)
This approach follows the approach of a single source of truth. If you later change your data layer to store data locally, none of the rest of your layers need to change. If Screen B gains the ability to edit your Holder
objects, then Screen A (assuming your data layer uses a Flow
or similar observable structure) would automatically update, without needing to pass data back or anything complicated like that.
It also means that cases which are generally hard to handle, such as configuration changes (i.e., rotating your device) or process death and recreation (which can happen at any screen, meaning you can't rely on Screen A to have loaded your data into memory) are also handled without any additional work.
Upvotes: 6