在 Compose 屏幕之间共享 MainActivity ViewModel

问题描述 投票:0回答:2

我正在使用 JetpackCompose,并且我有一个 lifecycle Observable BatteryBroadcast 类,该类使用 Hilt 注入到 MainActivity 中,我想 将数据从 BatteryBroadcast 传递到 ViewModel 以在可组合屏幕中使用该数据。那么如何在所有可组合的 Activity 屏幕中使用相同的 ViewModel 实例呢?我正在将 NavHost 用于可组合屏幕。

class MainActivity : ComponentActivity() {

    @Inject
    lateinit var batteryBroadcast: BatteryBroadcast

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        setContent {
            BatteryAlarmGoldTheme {

                val homeViewModel = hiltViewModel<HomeViewModel>()
                lifecycle.addObserver(batteryBroadcast)
                homeViewModel.setBatteryProfileData(batteryBroadcast.dataFlow)

                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    BatteryAlarmGoldApp()
                }
            }
        }
    }
}

我的撰写图。

fun NavGraphBuilder.homeNavGraph(
    navController: NavHostController
) {
    navigation(startDestination = Screen.HomeScreen.route, route = HOME_ROUTE) {
        composable(Screen.HomeScreen.route) {
            val homeBackStackEntry = remember { navController.getBackStackEntry(HOME_ROUTE) }
            val homeViewModel: HomeViewModel = hiltViewModel(homeBackStackEntry)

            HomeScreen(
                navController = navController,
                viewModel = homeViewModel
            )
        }
        composable(Screen.SelectRingtoneScreen.route) {
            val homeBackStackEntry = remember { navController.getBackStackEntry(HOME_ROUTE) }
            val homeViewModel: HomeViewModel = hiltViewModel(homeBackStackEntry)

            RingtoneScreen(
                viewModel = homeViewModel
            )
        }
    }
}

我尝试在 Compose 函数中@Inject BattryBroadcast,我还可以访问 ViewModel,以便我可以使用相同的 ViewModel 实例来设置和获取数据,但无法在 compose 函数中使用 @Inject。

android kotlin viewmodel android-jetpack-compose android-mvvm
2个回答
0
投票

为什么不将此视图模型实例传递到您的

BatteryAlarmGoldApp
可组合项中?

class MainActivity : ComponentActivity() {

    @Inject
    lateinit var batteryBroadcast: BatteryBroadcast

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        setContent {
            BatteryAlarmGoldTheme {

                val homeViewModel = hiltViewModel<HomeViewModel>()
                lifecycle.addObserver(batteryBroadcast)
                homeViewModel.setBatteryProfileData(batteryBroadcast.dataFlow)

                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    BatteryAlarmGoldApp(homeViewModel)
                }
            }
        }
    }
}

然后您可以在您的孩子可组合项中使用它


0
投票

也许更好的解决方案是将广播接收器制作为

@Composable
并将其包装在
DisposableEffect
中。

const val INTENT_ACTION_NFC_READ = "your.package.name.INTENT_ACTION_NFC_READ"

@Composable
fun NfcBroadcastReceiver(
    onScanSuccess: (Tag) -> Unit
) {
    val context = LocalContext.current
    val currentOnScanSuccessEvent by rememberUpdatedState(onScanSuccess)

    DisposableEffect(context) {
        val intentFilter = IntentFilter(INTENT_ACTION_NFC_READ)
        val broadcast = object : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                intent?.let {
                    when (intent.action) {
                        INTENT_ACTION_NFC_READ -> {
                            IntentCompat.getParcelableExtra(intent, NfcAdapter.EXTRA_TAG, Tag::class.java)
                                ?.let { currentOnScanSuccessEvent(it) }
                        }
                        else -> {
                            // No op.
                        }
                    }
                }
            }
        }

        ContextCompat.registerReceiver(
            context,
            broadcast,
            intentFilter,
            ContextCompat.RECEIVER_NOT_EXPORTED
        )

        onDispose {
            context.unregisterReceiver(broadcast)
        }
    }
}

然后在

@Composable
屏幕中使用它。

@Composable
fun SampleScreen() {

    NfcBroadcastReceiver(
        onScanSuccess = { tag ->
            // Handle tag
        }
    )

    Scaffold(
        modifier = ...,
        snackbarHost = ...,
        topBar = ...
    ) { padding ->
        { ... }
    }
}

当屏幕关闭时,

NfcBroadcastReceiver
将被丢弃。

© www.soinside.com 2019 - 2024. All rights reserved.