Jetpack 撰写更新列表元素
Jetpack compose update list element
我目前正在尝试为我的论文编写一个应用程序,目前,我正在研究不同的方法。由于我非常喜欢 Flutter,而且论文要求我使用 Java/Kotlin 我想使用 Jetpack compose。
目前,我无法尝试更新 ListElements。
我想要一个显示实验及其 state/result 的列表。一旦我按下按钮,我希望实验 运行 并在它们完成后更新它们的状态。目前,运行 方法除了将状态设置为成功外什么都不做。
问题是我不知道如何在实验更新其状态后从 ExperimentRow 的 viewModel 触发重组。
实验活动:
class ExperimentsActivity : AppCompatActivity() {
val exViewModel by viewModels<ExperimentViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//For now this is just Dummy Data and will be replaced
exViewModel.experiments += listOf(
Experiment("Test1", exViewModel::experimentStateChanged),
Experiment("Strongbox", exViewModel::experimentStateChanged)
)
setContent {
TpmTheme {
// A surface container using the 'background' color from the theme
Surface {
ExperimentScreen(
exViewModel.experiments,
exViewModel::startTests
)
}
}
}
}
}
ExperimentViewModel:
class ExperimentViewModel : ViewModel() {
var experiments by mutableStateOf(listOf<Experiment>())
fun startTests() {
for (exp in experiments) {
exp.run()
}
}
fun experimentStateChanged(experiment: Experiment) {
Log.i("ViewModel", "Changed expState of ${experiment.name} to ${experiment.state}")
// HOW DO I TRIGGER A RECOMPOSE OF THE EXPERIMENTROW FOR THE experiment????
//experiments = experiments.toMutableList().also { it.plus(experiment) }
Log.i("Vi", "Size of Expirments: ${experiments.size}")
}
}
实验屏幕:
@Composable
fun ExperimentScreen(
experiments: List<Experiment>,
onStartExperiments: () -> Unit
) {
Column {
LazyColumnFor(
items = experiments,
modifier = Modifier.weight(1f),
contentPadding = PaddingValues(top = 8.dp),
) { ep ->
ExperimentRow(
experiment = ep,
modifier = Modifier.fillParentMaxWidth(),
)
}
Button(
onClick = { onStartExperiments() },
modifier = Modifier.padding(16.dp).fillMaxWidth(),
) {
Text("Run Tests")
}
}
}
@Composable
fun ExperimentRow(experiment: Experiment, modifier: Modifier = Modifier) {
Row(
modifier = modifier
.padding(horizontal = 16.dp, vertical = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(experiment.name)
Icon(
asset = experiment.state.vAsset,
)
}
实验:
class Experiment(val name: String, val onStateChanged: (Experiment) -> Unit) {
var state: ExperimentState = ExperimentState.DEFAULT
set(value) {
field = value
onStateChanged(this)
}
fun run() {
state = ExperimentState.SUCCESS;
}
}
enum class ExperimentState(val vAsset: VectorAsset) {
DEFAULT(Icons.Default.Info),
RUNNING(Icons.Default.Refresh),
SUCCESS(Icons.Default.Done),
FAILED(Icons.Default.Warning),
}
有几种方法可以解决这个问题,但关键是您需要将元素的副本(状态已更改)添加到 experiments
以触发重组。
一个可能的例子是
data class Experiment(val name: String, val state: ExperimentState, val onStateChanged: (Experiment) -> Unit) {
fun run() {
onStateChanged(this.copy(state = ExperimentState.SUCCESS))
}
}
然后
fun experimentStateChanged(experiment: Experiment) {
val index = experiments.toMutableList().indexOfFirst { it.name == experiment.name }
experiments = experiments.toMutableList().also {
it[index] = experiment
}
}
尽管我怀疑这样做可能有更简洁的方法。
我目前正在尝试为我的论文编写一个应用程序,目前,我正在研究不同的方法。由于我非常喜欢 Flutter,而且论文要求我使用 Java/Kotlin 我想使用 Jetpack compose。
目前,我无法尝试更新 ListElements。
我想要一个显示实验及其 state/result 的列表。一旦我按下按钮,我希望实验 运行 并在它们完成后更新它们的状态。目前,运行 方法除了将状态设置为成功外什么都不做。 问题是我不知道如何在实验更新其状态后从 ExperimentRow 的 viewModel 触发重组。
实验活动:
class ExperimentsActivity : AppCompatActivity() {
val exViewModel by viewModels<ExperimentViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//For now this is just Dummy Data and will be replaced
exViewModel.experiments += listOf(
Experiment("Test1", exViewModel::experimentStateChanged),
Experiment("Strongbox", exViewModel::experimentStateChanged)
)
setContent {
TpmTheme {
// A surface container using the 'background' color from the theme
Surface {
ExperimentScreen(
exViewModel.experiments,
exViewModel::startTests
)
}
}
}
}
}
ExperimentViewModel:
class ExperimentViewModel : ViewModel() {
var experiments by mutableStateOf(listOf<Experiment>())
fun startTests() {
for (exp in experiments) {
exp.run()
}
}
fun experimentStateChanged(experiment: Experiment) {
Log.i("ViewModel", "Changed expState of ${experiment.name} to ${experiment.state}")
// HOW DO I TRIGGER A RECOMPOSE OF THE EXPERIMENTROW FOR THE experiment????
//experiments = experiments.toMutableList().also { it.plus(experiment) }
Log.i("Vi", "Size of Expirments: ${experiments.size}")
}
}
实验屏幕:
@Composable
fun ExperimentScreen(
experiments: List<Experiment>,
onStartExperiments: () -> Unit
) {
Column {
LazyColumnFor(
items = experiments,
modifier = Modifier.weight(1f),
contentPadding = PaddingValues(top = 8.dp),
) { ep ->
ExperimentRow(
experiment = ep,
modifier = Modifier.fillParentMaxWidth(),
)
}
Button(
onClick = { onStartExperiments() },
modifier = Modifier.padding(16.dp).fillMaxWidth(),
) {
Text("Run Tests")
}
}
}
@Composable
fun ExperimentRow(experiment: Experiment, modifier: Modifier = Modifier) {
Row(
modifier = modifier
.padding(horizontal = 16.dp, vertical = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(experiment.name)
Icon(
asset = experiment.state.vAsset,
)
}
实验:
class Experiment(val name: String, val onStateChanged: (Experiment) -> Unit) {
var state: ExperimentState = ExperimentState.DEFAULT
set(value) {
field = value
onStateChanged(this)
}
fun run() {
state = ExperimentState.SUCCESS;
}
}
enum class ExperimentState(val vAsset: VectorAsset) {
DEFAULT(Icons.Default.Info),
RUNNING(Icons.Default.Refresh),
SUCCESS(Icons.Default.Done),
FAILED(Icons.Default.Warning),
}
有几种方法可以解决这个问题,但关键是您需要将元素的副本(状态已更改)添加到 experiments
以触发重组。
一个可能的例子是
data class Experiment(val name: String, val state: ExperimentState, val onStateChanged: (Experiment) -> Unit) {
fun run() {
onStateChanged(this.copy(state = ExperimentState.SUCCESS))
}
}
然后
fun experimentStateChanged(experiment: Experiment) {
val index = experiments.toMutableList().indexOfFirst { it.name == experiment.name }
experiments = experiments.toMutableList().also {
it[index] = experiment
}
}
尽管我怀疑这样做可能有更简洁的方法。