jetpack组合更新列表元素

zrfyljdw  于 2021-07-08  发布在  Java
关注(0)|答案(1)|浏览(396)

我目前正试图为我的论文写一个应用程序,目前,我正在寻找不同的方法。因为我非常喜欢flutter,而且论文要求我使用java/kotlin,所以我想使用jetpack编写。
目前,我一直在尝试更新列表元素。
我想要一份显示实验及其状态/结果的列表。一旦我按下按钮,我希望实验运行,并在他们完成后更新他们的状态。目前,run方法除了将state设置为success之外什么也不做。问题是我不知道一旦一个实验更新了它的状态,如何从实验行的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),
}
lsmepo6l

lsmepo6l1#

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

尽管我怀疑有更干净的方法。

相关问题