从 Jetpack Compose 中的流追加到 LazyList

Append to LazyList from a flow in Jetpack Compose

我试图逐行读取文件,每一行都是 LazyList 中的一个新项目。我有一个我会订阅的流程,用于收听每一行新行

class LogcatService(private val coroutineScope: CoroutineScope) {
    private var _mutableLogcatListener: MutableSharedFlow<String> = MutableSharedFlow(0, 1, BufferOverflow.DROP_OLDEST)
    val logcatListener: SharedFlow<String> = _mutableLogcatListener

    private var _logcatJob: Job? = null

    fun startLogcat(){
        _logcatJob = coroutineScope.launch {
            Runtime.getRuntime().exec("logcat -c")
            Runtime.getRuntime().exec("logcat")
                .inputStream
                .bufferedReader()
                .useLines { lines ->
                    lines.forEach { newLine ->
                        _mutableLogcatListener.tryEmit(newLine)
                    }
                }
        }

    }

    fun stopLogcat(){
        _logcatJob?.cancel()
    }
}

然后在 activity 中,我会听流程附加已读取的每一行

@Composable
fun LogcatList(logcatService: LogcatService){
    val value = logcatService.logcatListener.collectAsState(initial = "")
    val content by remember { mutableStateOf(mutableListOf<String>())}
    content.add(value.value)
    LazyColumn {
        items(content) { message ->
            Text(text = message,
            )
        }
    }
}

但是我似乎没有在可组合项中获得任何流程更新。

我是 Jetpack Compose 的新手,所以我不知道自己做错了什么。使用常规 xml android 我只是将项目附加到 recyclerview 就是这样,但我正在尝试学习撰写。

这一行:

val content by remember { mutableStateOf(mutableListOf<String>()) }

应该给你以下警告:

Creating a MutableState object with a mutable collection type

可变状态是一个价值持有者。它只能在值本身发生变化时触发重组。但是它无法跟踪值状态何时发生变化——这就是你在改变可变列表时所做的。

您可以使用 mutableStateListOf:

val content = remember { mutableStateListOf<String>() }

此更改后应显示文本,如果您没有忘记 运行 startLogcat

您的代码中的另一个问题与此行有关:

content.add(value.value)

在 Compose 中,重组可能经常发生,在动画的情况下,每帧最多一次。它不应该导致您的代码出现问题,因为您只有一个状态发生变化,但通常直接从 @Composable 改变状态是一种不好的做法,请查看副作用 documentation and thinking in compose 中的更多内容。

在您的案例中更新 content 的正确方法如下所示:

LaunchedEffect(Unit) {
    logcatService.logcatListener
        .collect(content::add)
}

另一个解决方案是首先不使用 Flow,而是将 mutableStateListOf 直接移动到您的 LogcatService