raa*_*zza 3 android kotlin data-class android-jetpack android-jetpack-compose
我有一个数据类
data class Holder(uri: String, title: String, desc: String, source: String, color: String?)我从屏幕 a 获得的信息,我想将其传递到屏幕 b。我的代码设置如下:
@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)
}
)
}
Run Code Online (Sandbox Code Playgroud)
对此有何见解?
tl/dr:你根本不应该传递该对象,就像你看不到一个网站一样example.com/data/{the whole object in the URL},你会看到example.com/data/{a unique ID used to retrieve the object}
根据此线程,如果该对象仅存在于 UI 层(即,它不是来自远程数据库或任何其他事实来源),您可以按照文档直接传递该对象并创建您的类Parcelable和将其序列化以将其作为您的一部分,Screen.b.route就像任何其他参数一样。
但是,您说过您的Holder对象实际上来自远程数据库。同一个线程继续讨论这个案例:
开始对话的更好方法是弄清楚 StoreList 在进程死亡和重新创建后如何重新创建其列表。您的对象已从内存中完全擦除,这意味着 ViewModel 需要与实际的事实来源(即您的存储库层)对话 - 请注意,这并不意味着“保存到磁盘”或“数据库”,它只是意味着负责获取数据的层)
无论如何,一旦您拥有存储库层(因为 ViewModel 不应该直接进行网络调用或磁盘访问),这也是可以在内存缓存中执行的层
请记住,每个列表都已经有一种方法可以通过列表中的索引唯一地定义每个项目
因此,此时您已经拥有了所需的一切 - 两个目的地都可以与之通信的存储库,这是 Store 对象的单一事实来源以及列表中的索引,您可以将其传递到详细信息屏幕来定义元素
如果您开始将这些对象持久保存到数据库中,则其余层不必关心
(当然,如果您在某个时刻将每个元素添加到数据库中,您可能会为每个元素添加一个唯一的 ID,这使得基于索引的方法变得不必要)
所以你实际上应该如何做是:
创建一个负责加载数据的数据层。其他层不应该知道您的数据实际上来自远程数据库。Okhttp 缓存是一种添加缓存以防止以对其他层透明的方式重新下载数据的简单方法。
屏幕 A 和屏幕 B 都会与相同的数据层进行通信,通常,根据UI 层文档,将使用状态持有者(例如ViewModel负责从数据层加载数据的 a)。
Holder2a) 屏幕 A 将从数据层请求整个对象列表,数据层将从远程数据库加载整个列表。
2b) 屏幕 B 将仅请求一个Holder对象,方法是使用列表中的索引或唯一键(如果可用)(您的类不清楚Holder是否存在唯一键)
您不必将整个内容Holder作为屏幕 B 的路由参数的一部分传递,而只需传递该唯一键,该键可能只是列表中的索引,或者如果您的远程数据库具有这样一个唯一键(请注意,aUri将需要Uri.encode如果包含在路线中则通过编码)
这种方法遵循单一事实来源的方法。如果您稍后更改数据层以在本地存储数据,则其余层都不需要更改。如果屏幕 B 能够编辑Holder对象,则屏幕 A(假设您的数据层使用或Flow类似的可观察结构)将自动更新,而不需要传回数据或类似的复杂操作。
这也意味着通常难以处理的情况,例如配置更改(即旋转设备)或进程死亡和重新创建(这可能发生在任何屏幕上,这意味着您不能依赖屏幕 A 来加载数据到内存中)也可以在不需要任何额外工作的情况下进行处理。
| 归档时间: |
|
| 查看次数: |
1844 次 |
| 最近记录: |