从 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
。
我试图逐行读取文件,每一行都是 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
。