首页 > 解决方案 > 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),
}

标签: androidandroid-jetpack-compose

解决方案


有几种方法可以解决这个问题,但关键是您需要添加元素的副本(状态已更改)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
        }
    }

尽管我怀疑这样做可能有更清洁的方法。


推荐阅读