目前只有外部列表触发重组.当内部列表中的字符串也被更改/添加时,如何触发重新组合?

private var data by mutableStateOf<List<List<StringObject>>>(
    // Initialize with some sample data (20 rows, 10 columns)
    List(20) { outerIndex ->
        List(10) { innerIndex ->
            val value = "Value ${outerIndex * 10 + innerIndex + 1}"
            val imageUrl = if (innerIndex % 2 == 0)
                "https://example.com/image${innerIndex + 1}.jpg"
            else
                null
            StringObject(value, imageUrl)
        } as List<StringObject>
    }
)

我try 更换这个

mutableStateOf<List<List<StringObject>>>

用这个:

mutableStateOf<List<MutableList<StringObject>>>

但这会导致应用程序因并发修改而崩溃.我是作曲的新手,老实说,由于所有这些不可变和状态的东西,它很糟糕.新语言应该自己在内部管理这些东西.

java.util.ConcurrentModificationException
  at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1029)
  at java.util.ArrayList$Itr.next(ArrayList.java:982)
  at com.example.composetablee.MainActivity.addColumn(MainActivity.kt:143)
  at com.example.composetablee.MainActivity.access$addColumn(MainActivity.kt:28)
  at com.example.composetablee.MainActivity$onCreate$1$1$1$1$1$1$1.invoke(MainActivity.kt:51)
  at com.example.composetablee.MainActivity$onCreate$1$1$1$1$1$1$1.invoke(MainActivity.kt:51)
  at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$1$2.invoke-k-4lQ0M(Clickable.kt:167)
  at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$1$2.invoke(Clickable.kt:156)
  at androidx.compose.foundation.gestures.TapGestureDetectorKt$detectTapAndPress$2$1.invokeSuspend(TapGestureDetector.kt:255)
  at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
  at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:178)
  at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
  at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
  at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
  at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
  at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:328)
  at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter$PointerEventHandlerCoroutine.offerPointerEvent(SuspendingPointerInputFilter.kt:566)
  at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.dispatchPointerEvent(SuspendingPointerInputFilter.kt:456)
  at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.onPointerEvent-H0pRuoY(SuspendingPointerInputFilter.kt:469)
  at androidx.compose.ui.node.BackwardsCompatNode.onPointerEvent-H0pRuoY(BackwardsCompatNode.kt:374)
  at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:314)
  at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
  at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
  at androidx.compose.ui.input.pointer.NodeParent.dispatchMainEventPass(HitPathTracker.kt:183)
  at androidx.compose.ui.input.pointer.HitPathTracker.dispatchChanges(HitPathTracker.kt:102)
  at androidx.compose.ui.input.pointer.PointerInputEventProcessor.process-BIzXfog(PointerInputEventProcessor.kt:98)
  at androidx.compose.ui.platform.AndroidComposeView.sendMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1361)
  at androidx.compose.ui.platform.AndroidComposeView.handleMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1307)
  at androidx.compose.ui.platform.AndroidComposeView.dispatchTouchEvent(AndroidComposeView.android.kt:1246)
  at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3324)
  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2998)
  at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3324)
  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2998)
  at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3324)
  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2998)
  at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3324)
  at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2998)
  at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:776)
  at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1967)
  at android.app.Activity.dispatchTouchEvent(Activity.java:4522)
  at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:734)
  at android.view.View.dispatchPointerEvent(View.java:16476)
  at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:8490)

既然不可变列表不允许我在其中添加内容,该如何处理它?制作可变副本似乎资源成本高昂,尤其是如果您拥有一个大规模的列表数据列表.

Update 1- 这是当前的addStream函数

private fun addColumn() {
    data.withIndex().forEach { (index, row) -> // Use data.withIndex().forEach
        data[index].plus(ExcelCell("")) // Directly modify data
    }
}

重组仍未触发;( Recompisition not taken effect in innerList

推荐答案

如果您想创建列表列表,可以使用mutableStateListOf():

val parentList = mutableStateListOf<List<String>>(
    // pass List<String> instances in here
    listOf("A", "B"), listOf("M", "N"), listOf("X", "Y")
)

这将导致这样的 struct :

[
    ["A", "B"],
    ["M", "N"],
    ["X", "Y"]
]

要将新列表添加到parentList,请使用

parentList.add(listOf("1", "2"))

/*
Output:
[
    ["A", "B"],
    ["M", "N"],
    ["X", "Y"],
    ["1", "2"]
]
*/

要将新元素添加到parentList内的List中,请执行以下操作

parentList[2] = parentList[2].plus("Z")

/*
Output:
[
    ["A", "B"],
    ["M", "N"],
    ["X", "Y", "Z"],
    ["1", "2"]
]
*/

通过这种方法,Jetpack Compose应该能够正确地拾取对parentList或任何嵌套列表所做的更改.


你得到ConcurrentModificationException是因为你modify the MutableList while iterating over it.您可以通过使用迭代器来解决这个问题,如下面的代码所示:

@Composable
fun MainComposable() {

    val data = mutableStateListOf<List<String>>(
        // pass List<String> instances in here
        listOf("A", "B"), listOf("M", "N"), listOf("X", "Y")
    )

    Button(
        onClick = { 
            // use Iterator instead of forEach
            val iterate = data.listIterator()
            while (iterate.hasNext()) {
                val currentList = iterate.next()
                iterate.set(currentList.plus(""))  // update nested List safely
            }
        }
    ) {
        Text(text = "ADD COLUMN")
    }
}

另请注意,您不应将data变量全局存储在您的活动中.相反,它应该只在可组合的范围内声明.

单击按钮后,它会向data内的每个嵌套列表添加一个新的空字符串.相应调整以使用ExcelCell.

Android相关问答推荐

Android Compose Pages 3-一次加载所有页面,无需在LazyColumn中滚动,无需网络调用和内部滚动

每次重启Android时预填入Room数据库

如何使用Jetpack Compose实现此底表?

在Jetpack Compose中,如何判断屏幕是否已重新组合?

数据绑定在Android中等待填充值时显示未填充的值

使用 Gadle kotlin 为多模块 Android 代码库设置 jacoco

是否可以在 Android 应用程序的 Wifi 设置中为 DNS 服务器设置自定义 IP?

如何在 android compose 中将具有渐变边缘的透明圆圈绘制到阴影覆盖层中?

在compose中,为什么修改List元素的属性,LazyColumn不刷新

android xml底部空间大

在 Kotlin 中循环遍历字符串并用新行替换句号

删除项目时延迟列不更新

清洁架构中的服务

无法解析依赖项'com.github.smarteist:autoimageslider:1.4.0-appcompat'

Kotlin:如何在另一个变量的名称中插入一个变量的值

如何使用 Glide 将图像下载到设备内部存储

基线配置文件 x R8/Proguard

Jetpack Compose Tapjacking:过滤对模糊 UI 的touch

ObjectBox,如何在冲突中放弃一切迁移?

在使用 Retrofit 和 Room 时,我是否需要提及协程调度程序?