我试图在Jetpack Compose中测试ViewModel概念,我被这个问题难倒了,它让我花了一整天的时间无法弄清楚。在调试应用程序时,我看到ViewModel实际上正在更新,但它不会导致我的UI在更新后重新组合。
作为这个概念的一个更小的测试,我创建了一个应用程序,实际上只有一个文本和按钮元素组合。点击这个按钮是为了在更新ViewModel后改变文本; ViewModel会更新,但文本不会更改。我是基于示例代码进行编码的。我按照它的结构,100%准确,据我所知,但我的不工作。
如果我将工作演示代码复制粘贴到一个新的空白项目中,它就可以工作,所以很明显我遗漏了一些东西。我也试着一行一行地看它,没有发现任何可以解释原因的东西。如果我将自己的mutableStateOf变量添加到工作代码的视图模型中,并在其应用程序中使用它,也可以工作。如果我在工作代码中重命名变量,函数名等,它仍然有效。基本上,在演示代码中做任何事情都应该/预期地工作。但是从头开始创建一个完全遵循其格式的UI,它不会重新组合。
我用Text
和Button
创建了一个简单的测试应用程序。为它创建了一个ViewModel
扩展类的示例。单击Button
应该已经更改了Text
的内容。然而,什么都没有发生。但是ViewModel
扩展类中的值被更新了。没有与此问题相关的错误或警告,预览工作正常。
我的代码(不工作)
TestViewModel.kt:
class TestViewModel: ViewModel(){
var testVar by mutableStateOf("Hi")
fun changeText(){
testVar = "New"
}
}
MainActivity.kt:
class MainActivity: ComponentActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TestAppTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting(viewModel = viewModel())
}
}
}
}
}
@Composable
fun Greeting(viewModel: TestViewModel = viewModel()) {
DisplayOnScreen(testVar = viewModel.testVar, changeText = {viewModel.changeText()})
}
@Composable
fun DisplayOnScreen(testVar: String, changeText: () -> Unit){
Column() {
Text(testVar)
Button(onClick = {changeText}){
Text("Click")
}
}
}
@Preview (showBackground = true, showSystemUi = true)
@Composable
fun GreetingPreview(viewModel: TestViewModel = viewModel()) {
TestAppTheme {
Greeting(viewModel = viewModel())
}
}
演示代码(工作)
TestingViewModel.kt:
class TestingViewModel : ViewModel() {
var isCelsius by mutableStateOf(true)
var result by mutableStateOf("")
fun convertTemp(temp: String) {
result = try {
val tempInt = temp.toInt()
if (isCelsius) {
((tempInt * 1.8) + 32).roundToInt().toString()
} else {
((tempInt - 32) * 0.5556).roundToInt().toString()
}
} catch (e: Exception) {
"Invalid Entry"
}
}
fun switchChange() {
isCelsius = !isCelsius
}
}
MainActivity.kt:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
JustTheFilesTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
TestTop(viewModel = viewModel())
}
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun NewLines( isCelsius: Boolean, textState: String,
switchChange: () -> Unit, onTextChange: (String) -> Unit
) {
Row (verticalAlignment = Alignment.CenterVertically) {
Switch(checked = isCelsius, onCheckedChange = { switchChange() }
)
OutlinedTextField(value = textState, onValueChange = { onTextChange(it) },
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number
),
singleLine = true, label = { Text("Enter temperature") },
modifier = Modifier.padding(10.dp),
textStyle = TextStyle(fontWeight = FontWeight.Bold, fontSize = 30.sp),
trailingIcon = {
Icon(
painter = painterResource(R.drawable.baseline_ac_unit_24),
contentDescription = "frost", modifier = Modifier.size(40.dp)
)
}
)
Crossfade(
targetState = isCelsius, animationSpec = tween(2000), label = ""
) { visible ->
when (visible) {
true -> Text("\u2103", style = MaterialTheme.typography.headlineSmall)
false -> Text("\u2109", style = MaterialTheme.typography.headlineSmall)
}
}
}
}
@Composable
fun TestTop(viewModel: TestingViewModel = viewModel()) {
TempConvert(isCelsius = viewModel.isCelsius, result = viewModel.result,
convertTemp = { viewModel.convertTemp(it) },
switchChange = { viewModel.switchChange() }
)
}
@Composable
fun TempConvert( isCelsius: Boolean, result: String,
convertTemp: (String) -> Unit, switchChange: () -> Unit)
{
Column (horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()) {
var textState by remember { mutableStateOf("") }
val onTextChange = { text : String -> textState = text }
Text("Temperature Converter",
modifier = Modifier.padding(20.dp),
style = MaterialTheme.typography.headlineSmall
)
InputRow(
isCelsius = isCelsius, textState = textState,
switchChange = switchChange, onTextChange = onTextChange
)
Text (result, modifier = Modifier.padding(20.dp),
style = MaterialTheme.typography.headlineMedium
)
Button ( onClick = {convertTemp(textState) }
) { Text("Convert Temperature") }
}
}
@Preview(showBackground = true, showSystemUi = true)
@Composable
fun GreetingPreview(model: TestingViewModel = viewModel()) {
JustTheFilesTheme {
ScreenSetup(viewModel = viewModel())
}
}
2条答案
按热度按时间bwleehnv1#
您应该
remember
该值,以确保Compose框架成功跟踪更改。例如,在Greeting组合中,确保将状态值 Package 在remember
中(它还支持委托by
)。有了这个,Compose就知道该怎么做了。编辑:这似乎与Jetpack Compose本身无关,但与您修改文本的方式有关。在代码中,你似乎传递了一个lambda,但当你点击按钮时,你没有调用它,你只是调用lambda而没有调用,这就是我所说的:
应该是这样的吧?:
hujrc8aj2#
你需要传递整个viewModel而不仅仅是字符串