我有一个 GameState 对象,只要游戏状态发生变化,它就会更新,并且某些 UI 无法正确更新。我想在数据重新加载时调用重新加载函数,这样我就不必担心它不更新。
package dev.madcatter.lostworld
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.lifecycleScope
import dev.madcatter.lostworld.data.GameState
import dev.madcatter.lostworld.ui.Console
import dev.madcatter.lostworld.ui.Turns
import dev.madcatter.lostworld.ui.theme.LostWorldTheme
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
private lateinit var myApp: LostWorldApp
private lateinit var gameState: MutableState<GameState>
private var updateTicker: MutableState<Int> = mutableStateOf(0)
@OptIn(ExperimentalMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
myApp = application as? LostWorldApp ?: throw IllegalStateException("Application class is not LostWorldApp")
gameState = mutableStateOf(myApp.gameState!!)
enableEdgeToEdge()
setContent {
LostWorldTheme {
MainContent()
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun MainContent() {
Scaffold(
topBar = {
TopAppBar(
title = { Text(text = "Lost World") },
actions = {
IconButton(onClick = {
gameState.value.debug("---\n\nReload button clicked.")
reloadGameState()
}) {
Icon(
imageVector = Icons.Default.Refresh,
contentDescription = "Reload"
)
}
IconButton(onClick = {
startActivity(Intent(this@MainActivity, SettingsActivity::class.java))
}) {
Icon(
imageVector = Icons.Default.Settings,
contentDescription = "Settings"
)
}
}
)
},
content = { innerPadding ->
// Main content here
Row(modifier = Modifier.padding(innerPadding)) {
Turns(
gameState.value,
modifier = Modifier
.padding(16.dp)
.weight(0.25f)
.fillMaxHeight()
)
VerticalDivider(
color = MaterialTheme.colorScheme.outline,
modifier = Modifier
.width(1.dp)
.align(Alignment.CenterVertically)
.fillMaxHeight(0.85f)
)
Console(
gameState.value,
modifier = Modifier
.padding(16.dp)
.weight(0.75f)
.fillMaxHeight()
)
}
}
)
}
override fun onStart() {
super.onStart()
// Run the reload after a short delay using lifecycleScope
lifecycleScope.launch(Dispatchers.Main) {
delay(200) // Wait 200 milliseconds, or adjust as necessary
reloadGameState()
}
}
private fun reloadGameState() {
gameState.value.reload()
gameState.value = myApp.gameState!!
updateTicker.value++
}
}
使用 jetpack compose 时,切勿手动更新 UI。它只会扼杀开发撰写应用程序的理由。我可以看到这是你的游戏对象。
gameState: MutableState<GameState>
如果您需要jetpack compose在对象状态发生变化时更新UI。您必须使用记住 API。因此,如果您像下面这样更改对象,您的 UI 应该会自动更新。
val state by remember{
mutableStateOf(myApp.gameState!!)
}
如果只是更新对象的特定属性并期望更新 UI,您可以使用复制功能使其工作。
state = state.copy(prop = ?)
我希望这有帮助。