android 尝试使用Jetpack Compose理解ViewModels和Navigation

tez616oj  于 12个月前  发布在  Android
关注(0)|答案(1)|浏览(134)

我试图理解如何使用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中的变量值?
谢谢你考虑我的问题,我真的很感激!

mzsu5hc0

mzsu5hc01#

有两种方法可以共享数据。
首先,你可以通过使用导航参数来传递参数。传递一些值并在屏幕上获取值。https://developer.android.com/jetpack/compose/navigation#nav-with-args
第二,使用存储库层来共享一些数据。在存储库中公开一个流,并在ViewModel中收集此值。然后,通过存储库中的流发出一些数据。https://developer.android.com/topic/architecture/data-layer
也许,你可以通过修改NavigationAppHost函数来传递viewModel,而不是像下面这样创建新的示例,来与一个ViewModel共享数据。

@Composable
fun NavigationAppHost (navController: NavController, viewModel: MainViewModel) {

    NavHost(navController = navController as NavHostController, startDestination = "PlayerSelection") {
        composable(Destination.PlayerSelection.route)  { PlayerSelection(navController, viewModel) }
        composable(Destination.TwoPlayerGame.route) {TwoPlayerGame(navController, viewModel)}
        composable(Destination.ThreePlayerGame.route) {ThreePlayerGame(navController, viewModel)}
        composable(Destination.FourPlayerGame.route) {FourPlayerGame(navController, viewModel)}
    }
}

字符串
AAC(Android架构组件)建议每个屏幕使用一个ViewModel。因为它保存了特定的UI状态,当配置发生更改时可以被销毁。但是,MVVM模式还有另一种观点,比如在多个屏幕上重用ViewModel。您可以引用AAC ViewModelMVVM ViewModel
这里有很好的例子来学习ViewModel和导航与Jetpack Compose. https://github.com/android/socialite
https://github.com/android/nowinandroid [高级]

相关问题