From cf145b53740719c1743a0b5b35240431b8194174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 21 Mar 2026 12:40:41 +0800 Subject: [PATCH] Dispatch log callbacks to main thread Move allLogs/bufferedLogs mutations in appendLogs, clearLogs, and setDefaultLogLevel into viewModelScope.launch(Dispatchers.Main) to avoid concurrent iteration from the search debounce flow. --- .../sfa/compose/screen/log/LogViewModel.kt | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/io/nekohasekai/sfa/compose/screen/log/LogViewModel.kt b/app/src/main/java/io/nekohasekai/sfa/compose/screen/log/LogViewModel.kt index 601a51d..ecaf56d 100644 --- a/app/src/main/java/io/nekohasekai/sfa/compose/screen/log/LogViewModel.kt +++ b/app/src/main/java/io/nekohasekai/sfa/compose/screen/log/LogViewModel.kt @@ -81,15 +81,19 @@ class LogViewModel : override fun setDefaultLogLevel(level: Int) { val logLevel = LogLevel.entries.find { it.priority == level } ?: error("Unknown log level: $level") - _uiState.update { it.copy(defaultLogLevel = logLevel) } - updateDisplayedLogs() + viewModelScope.launch(Dispatchers.Main) { + _uiState.update { it.copy(defaultLogLevel = logLevel) } + updateDisplayedLogs() + } } override fun clearLogs() { - allLogs.clear() - bufferedLogs.clear() - _uiState.update { it.copy(isPaused = false) } - updateDisplayedLogs() + viewModelScope.launch(Dispatchers.Main) { + allLogs.clear() + bufferedLogs.clear() + _uiState.update { it.copy(isPaused = false) } + updateDisplayedLogs() + } } override fun requestClearLogs() { @@ -104,23 +108,25 @@ class LogViewModel : override fun appendLogs(message: List) { val processedLogs = message.map { processLogEntry(it) } - if (_uiState.value.isPaused) { - bufferedLogs.addAll(processedLogs) - } else { - val totalSize = allLogs.size + processedLogs.size - val removeCount = (totalSize - maxLines).coerceAtLeast(0) + viewModelScope.launch(Dispatchers.Main) { + if (_uiState.value.isPaused) { + bufferedLogs.addAll(processedLogs) + } else { + val totalSize = allLogs.size + processedLogs.size + val removeCount = (totalSize - maxLines).coerceAtLeast(0) - if (removeCount > 0) { - repeat(removeCount) { - allLogs.removeFirst() + if (removeCount > 0) { + repeat(removeCount) { + allLogs.removeFirst() + } } - } - allLogs.addAll(processedLogs) - updateDisplayedLogs() + allLogs.addAll(processedLogs) + updateDisplayedLogs() - if (_autoScrollEnabled.value && !_uiState.value.isPaused && !_uiState.value.isSearchActive) { - scrollToBottom() + if (_autoScrollEnabled.value && !_uiState.value.isPaused && !_uiState.value.isSearchActive) { + scrollToBottom() + } } } }