我试图理解如何使用ViewModel,它保存可以传递到不同屏幕的值。
我写了一个非常简单的程序来尝试理解这个概念。
以下是我的主要活动:
sealed class Destination(val route: String) {
object PlayerSelection: Destination("PlayerSelection")
object TwoPlayerGame: Destination("TwoPlayerGame")
object ThreePlayerGame: Destination("ThreePlayerGame")
object FourPlayerGame: Destination("FourPlayerGame")
}
class MainActivity : ComponentActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Viewmodels_and_NavigationTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
ScreenSetup(viewModel)
}
}
}
}
}
字符串
下面是我的NavigationAppHost:
@Composable
fun NavigationAppHost (navController: NavController, viewModel: MainViewModel) {
NavHost(navController = navController as NavHostController, startDestination = "PlayerSelection") {
composable(Destination.PlayerSelection.route) { PlayerSelection(navController,MainViewModel()) }
composable(Destination.TwoPlayerGame.route) {TwoPlayerGame(navController,MainViewModel())}
composable(Destination.ThreePlayerGame.route) {ThreePlayerGame(navController,MainViewModel())}
composable(Destination.FourPlayerGame.route) {FourPlayerGame(navController,MainViewModel())}
}
}
型
下面是我的ScreenSetup:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ScreenSetup(viewModel: MainViewModel) {
//Navigation Stuff
val navController = rememberNavController()
Scaffold(
topBar = { TopAppBar(title = { Text(text = "Viewmodels and Navigation") }) },
content = { padding ->
Column(Modifier.padding(padding)) {
NavigationAppHost(navController = navController,viewModel)
}
},
bottomBar = { Text(text = "BottomBar") }
)
}
型
以下是Composable PlayerSelection:
@Composable
fun PlayerSelection(navController: NavController, viewModel: MainViewModel) {
val HowManyPlayers: Int by viewModel.howManyPlayers.collectAsState()
Column {
Row {
Text(text = "How Many Players?")
}
Row() {
Button(onClick = { viewModel.Selection(2) }) {
Text("Two Players")
}
Button(onClick = { viewModel.Selection(3) }) {
Text("Three Players")
}
Button(onClick = { viewModel.Selection(4) }) {
Text("Four Players")
}
}
Row() {
Text(text = "Current Value Held in MainViewModel = ${HowManyPlayers}")
}
Button(onClick = {
if (HowManyPlayers == 2) {
navController.navigate(Destination.TwoPlayerGame.route)
}
if (HowManyPlayers == 3) {
navController.navigate(Destination.ThreePlayerGame.route)
}
if (HowManyPlayers == 4) {
navController.navigate(Destination.FourPlayerGame.route)
}
}) {
Text(text = "Click To Navigate To Next Screen")
}
}
}
型
下面是MainViewModel:
class MainViewModel : ViewModel() {
var _howManyPlayers = MutableStateFlow(0)
var howManyPlayers = _howManyPlayers.asStateFlow()
fun Selection(players:Int) {
_howManyPlayers.value = players
}
}
型
下面是TwoPlayerGame Composable:
@Composable
fun TwoPlayerGame(navController: NavController, viewModel: MainViewModel) {
val howManyPlayers by viewModel.howManyPlayers.collectAsState()
Column {
Row(Modifier.padding(50.dp)) {
Text(text = "Two Player Game")
}
Row {
Text(text = "Value of howManyPlayers in viewmodel = ${howManyPlayers}")
}
}
}
型
当用户在PlayerSelection屏幕中选择多少个玩家时,MainViewModel中的HowManyPlayers变量会根据用户按下的按钮成功更改。我可以看到这一行的工作情况:
第一个月
这很酷。然而,当我点击按钮导航到TwoPlayerGame时,MainViewModel中的变量HowManyPlayers再次重置为0。为什么在导航到新屏幕时,MainViewModel中的HowManyPlayers值重置为0?是否有一种方法可以将ViewModel传递到不同的屏幕,同时保留传递的ViewModel中的变量值?
谢谢你考虑我的问题,我真的很感激!
1条答案
按热度按时间mzsu5hc01#
有两种方法可以共享数据。
首先,你可以通过使用导航参数来传递参数。传递一些值并在屏幕上获取值。https://developer.android.com/jetpack/compose/navigation#nav-with-args
第二,使用存储库层来共享一些数据。在存储库中公开一个流,并在ViewModel中收集此值。然后,通过存储库中的流发出一些数据。https://developer.android.com/topic/architecture/data-layer
也许,你可以通过修改
NavigationAppHost
函数来传递viewModel
,而不是像下面这样创建新的示例,来与一个ViewModel共享数据。字符串
AAC(Android架构组件)建议每个屏幕使用一个ViewModel。因为它保存了特定的UI状态,当配置发生更改时可以被销毁。但是,MVVM模式还有另一种观点,比如在多个屏幕上重用ViewModel。您可以引用AAC ViewModel,MVVM ViewModel
这里有很好的例子来学习ViewModel和导航与Jetpack Compose. https://github.com/android/socialite
https://github.com/android/nowinandroid [高级]