遵循本教程。我创建了 ViewModel 并希望将其公开给 GameScreen () 可组合项。我不断收到错误“无法实例化 ViewModel”,预览无法渲染,并且应用程序在模拟器中不断崩溃。
我知道这是合法的,因为解决方案代码有效! 解决方案代码
可组合:
@Composable
fun GameScreen(
gameViewModel: GameViewModel = viewModel()
) {
val gameUiState by gameViewModel.uiState.collectAsState()
/*
rest of composable
*/
这是 ViewModel 类(GameViewModel.kt):
package com.example.unscramble.ui
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import com.example.unscramble.data.allWords
/*viewmodel contains functionality of the app picking words, shuffling, resetting
* is immutable to other classes (read-only)
* */
class GameViewModel : ViewModel() {
// Game UI state
private val _uiState = MutableStateFlow(GameUiState())
var userGuess by mutableStateOf("")
private set
// Backing property to avoid state updates from other classes
val uiState: StateFlow<GameUiState> = _uiState.asStateFlow()
init {
resetGame()
}
fun resetGame() {
usedWords.clear()
_uiState.value = GameUiState(currentScrambledWord = pickRandomWordAndShuffle())
}
private lateinit var currentWord: String
// Set of words used in the game
private var usedWords: MutableSet<String> = mutableSetOf()
private fun pickRandomWordAndShuffle(): String {
// Continue picking up a new random word until you get one that hasn't been used before
currentWord = allWords.random()
if (usedWords.contains(currentWord)) {
return pickRandomWordAndShuffle()
} else {
usedWords.add(currentWord)
return shuffleCurrentWord(currentWord)
}
}
private fun shuffleCurrentWord(word: String): String {
val tempWord = word.toCharArray()
// Scramble the word
tempWord.shuffle()
while (String(tempWord).equals(word)) {
tempWord.shuffle()
}
return String(tempWord)
}
}
我已经编辑了使用 ViewModel 的项目的依赖关系,如下所示
当前配置
dependencies {
implementation(platform("androidx.compose:compose-bom:2023.08.00"))
implementation("androidx.activity:activity-compose:1.8.0")
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0")
我已将问题范围缩小到 GameViewModel.kt 中的这两行
init {
resetGame()
}
fun resetGame() {
usedWords.clear()
_uiState.value = GameUiState(currentScrambledWord = pickRandomWordAndShuffle())
}
如果我注释掉resetGame()中的行。视图模型被实例化,即工作并呈现预览。如果我取消注释“usedWords.clear()”或“_uiState.value = GameUiState(currentScrambledWord = pickRandomWordAndShuffle())”,则视图模型无法实例化。
为什么这两行会阻止视图模型的实例化?继续注释掉的行,但最终需要添加此功能。
非常愚蠢,移动“usedWords”的 var 声明上面函数定义消除了我的错误。必须打破一些语法规则,使“GameViewModel.kt”类非法/损坏。
改变
类 GameViewModel : ViewModel() {
// Game UI state
private val _uiState = MutableStateFlow(GameUiState())
var userGuess by mutableStateOf("")
private set
// Backing property to avoid state updates from other classes
val uiState: StateFlow<GameUiState> = _uiState.asStateFlow()
init {
resetGame()
}
fun resetGame() {
usedWords.clear()
_uiState.value = GameUiState(currentScrambledWord = pickRandomWordAndShuffle())
}
private lateinit var currentWord: String
// Set of words used in the game
private var usedWords: MutableSet<String> = mutableSetOf()
至
class GameViewModel : ViewModel() {
// Game UI state
private val _uiState = MutableStateFlow(GameUiState())
// Set of words used in the game
private var usedWords: MutableSet<String> = mutableSetOf()
var userGuess by mutableStateOf("")
private set
// Backing property to avoid state updates from other classes
val uiState: StateFlow<GameUiState> = _uiState.asStateFlow()
init {
resetGame()
}
fun resetGame() {
usedWords.clear()
_uiState.value = GameUiState(currentScrambledWord = pickRandomWordAndShuffle())
}
成功了。