android - Jetpack 撰写更新列表元素
问题描述
我目前正在尝试为我的论文编写一个应用程序,目前,我正在研究不同的方法。因为我真的很喜欢 Flutter 并且论文要求我使用 Java/Kotlin,所以我想使用 Jetpack compose。
目前,我一直在尝试更新 ListElements。
我想要一个显示实验及其状态/结果的列表。一旦我点击按钮,我希望实验运行并在它们完成后更新它们的状态。目前, run 方法除了将状态设置为成功之外什么都不做。问题是一旦实验更新其状态,我不知道如何从 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
)
}
}
}
}
}
实验视图模型:
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
}
}
尽管我怀疑这样做可能有更清洁的方法。
推荐阅读
- python - 从 DXF 导入时如何查找连接的线和弧?
- matlab - 如何在 Matlab 中将其编写为函数?(矢量)
- prometheus - 联合普罗米修斯
- amp-html - amp-autocomplete:选择选项后如何提交表单?
- java - 如何从另一个 Java 类调用 GUI 表单
- c# - 如何将 UserControl 转换为控件
- android - 如何更改 Android TextViews 中的背景颜色 BlockQuotes?
- r - 如何总结数据点之间的重叠
- c# - 如何使用 selenium c# 处理网页上的两个垂直滚动
- algorithm - 有向伪图中的所有可能路径