跟着 UI 架构的变迁和技术的迭代,界面间数据传递的方法也变得多种多样了。没有最好的方法,只要当时合适事务的方法。今天咱们就来看看有哪些数据传递的方法,咱们又该怎样选择?

在最开端的时分,界面仅仅运用 startActivityForResult 来进行页面间的数据传递,后边 Fragment 诞生,官方也供给了 FragmentManager.setFragmentResultListener 之类的方法,但 Jetpack Compose 之后,官方就完全弱化了这方面的才能。

在探索详细的技术细节前,咱们要先看看咱们数据需求传输的场景有哪些:

  1. 启动新界面是为了获取某些数据,然后回来给当时界面用,例如相片选择器。
  2. 几个界面是为了合作完结一件工作,每个界面担任一部分流程,例如注册流程。
  3. 界面的某些改动,需求告诉到其它界面,例如用户关注的改变,一旦改变,则希望其它界面也可以同步更新。

大多数状况下,咱们所说的数据传输都是针对第一种状况而言。最基础的便是 startActivityForResult。当然,现在应该没人直接用这个了,都是用官方封装的 LauncherForActivityResult 了:

val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.GetContent(), onResult = {uri ->
    // ...
})

如果运用的是 Fragment, 曾经可以运用十分不好用的 setTargetFragment, 现在则可以运用 FragmentManager.setFragmentResultListener,与 Activity 的运用是迥然不同。

而如果是运用 Jetpack Compose Navigation, 那不好意思,现在还十分不成熟,一个可用的方法是运用 previousBackStackEntry:

// 新界面运用 previousBackStackEntry 获取到前一个界面的数据存储,然后往里面设置数据
navController.previousBackStackEntry
    ?.savedStateHandle
    ?.set("your_key", "your_value")
navController.popBackStack()
// 回来到原本的界面后,经过 currentBackStackEntry 去读取数据存储。
val savedStateHandle = navController.currentBackStackEntry?.savedStateHandle

虽然咱们也可以参照 Fragment 的完结用 ActivityViewModel 构建一套 ComposeResultListener 之类的完结。但估计跟着版别的迭代和大众的呼声,官方也会出品接口更友爱的方法。而如果咱们自己完结的话,就可以在官方出品后对比下,看看差距,才知道怎样写出更好的代码。

但需求记住的是,这二者都是不能跨越 Activity 而通信的。如果是多 ActivityPage 架构,则需求注意这种状况。我觉得,这种界面一般是通用型的组件界面,所以一般运用 Activity 作为载体就好。

如果是几个界面合作完结某件工作,需求相互共享一些数据,那就可以把这几个界面包裹在同一个 Activity 里,运用 ActivityViewModel 作为数据的载体,每个界面监听 ActivityViewModel 的数据,那么便是完美的数据驱动 UI 了。

emophoto 库中,相片选择器有 grid 界面、preview 界面、edit 界面,其三者都收归在 PhotoPickerActivity, 共享 PhotoPickerViewModel 来进行数据管理, 最后再经过 ActivityResult 交给外部调用者,这也是第一种方法与第二种方法的结合。

而事务上运用最常见的方法应该是第三种了,便是我增修改查了些数据,希望其它界面也可以立刻同步到,不要呈现各个界面不对齐的状况。ChannelStateFlowSharedFlow 等数据流东西都可以助力咱们数据驱动 UI,当然,最便利的形式便是运用 emo 封装的 EmoBus

// 界说数据改变事情
data class AddCommentSuccessEvent(val thinkId: Long, val id: Long, val draftId: Long)
// A 界面发送事情
EmoBus.default.emit(AddCommentSuccessEvent(content.itemId, id, draft.id))
// B 界面监听事情
EmoBus.default.flowOf<AddCommentSuccessEvent>().collect {
    // ...
}

基本上咱们可以用于页面间数据传递与运用的就这些形式了,咱们只需求在需求的场景选用恰当的方法就可以了。


我是古哥E下,前微信读书客户端程序猿 / 自学 5 年中医,保护过上万 Star 开源项目 QMUI Android,现独立保护好用简练的 Android 组件库 emo

关注我可得:ChatGPT 开发玩法 | 程序员学习经验 | 组件库新变动 | 中医健康调度 。

emo官网:emo.qhplus.cn