Skip to content
阅读进度

Android 怎样展示流式回答,避免卡顿、重复和串消息? ​

返回 性能与稳定性 目录

标准回答 ​

我会把网络接收、协议解析、消息状态和 UI 展示分开。网络读取到的一块字节不一定是一条完整事件,更不一定是一个 token;UTF-8 字符和 JSON 也可能跨块。先用正确的流式解码和协议解析器还原事件,再交给消息状态管理。

每次生成分配 requestId,并把增量关联到明确的 conversationId 和 messageId。数据层累计文本,维护生成中、完成、失败、已取消等状态;UI 只观察当前会话的有效状态。重复或迟到事件按服务协议里的序号、事件标识或本地任务版本处理,不能把所有收到的字符串无条件追加。

主线程不做大量 JSON 或 Markdown 解析,也不必每来一小段就重绑整个列表。我会合并短时间内的更新,只刷新正在生成的条目,必要时降低复杂富文本解析频率;最终完成时补齐最后一批内容。用户正在向上阅读时,也不强制每次滚动到底部。

用户取消、切换会话或页面销毁时,更新订阅与任务状态,并按任务归属决定是否取消网络请求。重连能否续传要看服务端协议:有事件标识不等于服务端一定保存历史;不支持续传时,明确中断或新建一次生成,不能把新回答误接到旧回答后面。

关键机制 ​

  • 网络分块、协议事件、模型 token 和一次 UI 更新是四种边界。
  • 消息标识与任务版本防串流;序号或事件 ID 去重必须配合服务端语义。
  • 合并更新、局部刷新、按生命周期订阅;完成和取消都要结束对应状态。

通俗例子 ​

用户先问 A,随即取消并问 B。A 的最后一段稍后到达:状态层发现 requestId 已失效,丢弃这段 UI 更新。B 的回答继续展示,不会混入 A 的文本。

追问与回答 ​

SSE 和 WebSocket 怎么选? ​

如果主要是客户端发起一次请求,服务端持续下发生成结果,基于 HTTP 的流式响应或 SSE 往往就够。需要持续双向交互的场景再评估 WebSocket。选择后还要定义心跳、取消、重连和业务事件;换一种传输方式并不会自动解决重复、错序或生命周期问题。

为什么不能每收到一个 token 就刷新? ​

首先客户端收到的事件不一定对应单个 token。其次高频刷新可能重复做文本排版、Markdown 解析和列表布局,导致主线程忙于中间状态。我会保持数据完整接收,但按短时间窗口或帧节奏合并可见更新,最终内容不丢,显示延迟则通过实测控制。

易混淆点 ​

SSE 提供事件格式和可选事件 ID;它不自动提供服务端持久化、严格去重或任意 Android 客户端的断点续传。连接断开也不能擅自当作业务生成成功。

参考资料 ​

内容来源 ​

用完整回答理解机制,用真实证据解释项目。