Jetpack Compose 中在屏幕间共享数据的 5 种方案

本文介绍了在Jetpack Compose中屏幕间共享数据的5种方法:1) 路由传参,适用于简单数据传递;2) 共享ViewModel,适用于跨配置变更的数据共享;3) 单例StateFlow,风险在于进程重启后数据丢失;4) CompositionLocal,仅限父子组件间共享;5) 持久化存储,能永久保存数据但速度较慢。每种方案都有其适用场景和限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 路由传参

Jetpack Compose 中路由传参的方式有很多种,具体可以参考 Jetpack Compose 中的导航路由

以下是最简单的路由传参测试代码:

import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument

@Composable
fun NavigationArgsSample() {
   
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = "screen1"
    ) {
   
        composable("screen1") {
   
            Screen1(onNavigateToScreen2 = {
   
                navController.navigate("screen2/$it")
            })
        }
        composable(
            route = "screen2/{my_param}",
            arguments = listOf(
                navArgument("my_param") {
   
                    type = NavType.StringType
                }
            )
        ) {
   
            val param = it.arguments?.getString("my_param") ?: ""
            Screen2(param = param)
        }
    }
}

@Composable
private fun Screen1(onNavigateToScreen2: (String) -> Unit) {
   
    Button(onClick = {
   
        onNavigateToScreen2("Hello world!")
    }) {
   
        Text(text = "Click me")
    }
}

@Composable
private fun Screen2(param: String) {
   
    Text(text = param)
}

代码很简单,就是从Screen1路由页面传一个值给Screen2路由页面。

这种方式不能算是真正的共享数据,它只能算是 “把我的数据分享给别人” 这种概念,当参数值到达别的页面以后,就成为该页面的本地静态数据,如果你修改了该数据也不会反馈到原始路由页面中。但是只从分享数据的角度,这种方式足够简单。

另外这种方式有一个好处是可以跨越系统内存不足杀死进程的情况而存活

我们可以通过 Android Studio Logcat 面板的 “Terminate Application” 按钮来模拟系统内存不足杀死进程的情况,但是当我打开我的 Android Studio 之后,不禁发出灵魂拷问:Where did my “Terminate Application” button gone ? 😑

在这里插入图片描述

好家伙,这个按钮居然没有了,如果你使用的是 Android Studio Dolphin 或者 Android Studio Flamingo 一定也会遇到这个问题,这个按钮对于模拟系统终止应用进程的场景还是非常有用的(注意它的作用不同于顶部工具栏中的stop按钮)。该怎么把它找回来呢?

不用慌,经过一番搜索,终于找到了该怎么把它找回来:Settings --> Experimental --> Enable new Logcat tool window. 将这个选项的打勾取消即可。

然后我们运行应用,将路由跳转到Screen2然后回到后台,这时点击 Terminate Application 模拟系统杀进程,效果如下:

在这里插入图片描述

可以发现这种方式确实可以在系统回收应用进程后,再次打开应用时,仍然保持之前的页面状态。

这种方式缺点也很明显,假如我们路由导航路径上有 7 个屏幕,不可能将数据从第一个传到第七个,那样太麻烦了。

2. 共享ViewModel

我们知道ViewModel可以跨越Activity的配置变更而存活,因此它是一个Activity中不同的Composable组件之间共享数据的绝佳方案:

在这里插入图片描述

实际上ViewModel的作用域被限定为一个离他最近的 ViewModelStoreOwnerLifecycle。它会一直保留在内存中,直到其 ViewModelStoreOwner 永久消失。

ViewModelStoreOwner 对象可能是一个 ActivityFragment 或者一个 Navigation 导航图(NavBackStackEntry),具体取决于使用的场景。

如果我们打算在一个导航图之内的不同路由之间通过ViewModel来共享数据,就可以将其作用域限定为该导航图。

下面开始测试,首先创建一个用于共享的SharedViewModel

import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow

class SharedViewModel: ViewModel() {
   

    private val _sharedState = MutableStateFlow(0)
    val sharedState = _sharedState.asStateFlow()

    fun updateState() {
   
        _sharedState.value++
    }

    override fun onCleared() {
   
        super.onCleared()
        println("ViewModel cleared")
    }
}

测试代码:

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navigation
import com.fly.mycompose.application.examples.sharedata.model.SharedViewModel

@Composable
fun SharedViewModelSample() {
   
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = "onboarding"
    ) {
   
        navigation(
            startDestination = "personal_details",
            route = "onboarding"
        ) {
   
            composable(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

川峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值