优化(UI): 修复 Markdown 渲染导致的内存抖动

将 Markwon 解析引擎的 builder 创建逻辑提取到 LazyColumn 的外部并记忆化(remember),将其作为参数传入每一条消息的渲染组件中。
这避免了在聊天列表滚动时,每条消息都会高频实例化一个极度消耗资源的全新的 Markwon 引擎,从而极大减少了短命对象的创建和 GC 压力。
This commit is contained in:
fengge 2026-06-03 14:48:58 +08:00
parent 89f1df9a9b
commit e266a4e690
1 changed files with 14 additions and 13 deletions

View File

@ -40,6 +40,18 @@ fun ChatArea(
}
}
val context = androidx.compose.ui.platform.LocalContext.current
val markwon = remember(context) {
io.noties.markwon.Markwon.builder(context)
.usePlugin(io.noties.markwon.core.CorePlugin.create())
.usePlugin(io.noties.markwon.ext.tables.TablePlugin.create(context))
.usePlugin(io.noties.markwon.html.HtmlPlugin.create())
.usePlugin(io.noties.markwon.linkify.LinkifyPlugin.create())
.usePlugin(io.noties.markwon.ext.strikethrough.StrikethroughPlugin.create())
.usePlugin(io.noties.markwon.ext.tasklist.TaskListPlugin.create(context))
.build()
}
val isAnyStreaming = remember(messages) { messages.any { it.isStreaming } }
if (isAnyStreaming) {
val totalLength = messages.map { it.content.length }.sum()
@ -111,6 +123,7 @@ fun ChatArea(
val contentWithCursor = msg.content + if (msg.isStreaming) "" else ""
MarkwonRenderer(
markdown = contentWithCursor,
markwon = markwon,
modifier = Modifier.padding(12.dp)
)
}
@ -161,19 +174,7 @@ fun ChatArea(
}
@Composable
fun MarkwonRenderer(markdown: String, modifier: Modifier) {
val context = androidx.compose.ui.platform.LocalContext.current
val markwon = remember(context) {
io.noties.markwon.Markwon.builder(context)
.usePlugin(io.noties.markwon.core.CorePlugin.create())
.usePlugin(io.noties.markwon.ext.tables.TablePlugin.create(context))
.usePlugin(io.noties.markwon.html.HtmlPlugin.create())
.usePlugin(io.noties.markwon.linkify.LinkifyPlugin.create())
.usePlugin(io.noties.markwon.ext.strikethrough.StrikethroughPlugin.create())
.usePlugin(io.noties.markwon.ext.tasklist.TaskListPlugin.create(context))
.build()
}
fun MarkwonRenderer(markdown: String, markwon: io.noties.markwon.Markwon, modifier: Modifier) {
androidx.compose.ui.viewinterop.AndroidView(
factory = { ctx ->
val textView = SafeSelectableTextView(ctx).apply {