背景
最近使用okhttp+SSE请求大模型接口,拿到流式数据后,刷新RecyclerView里Item布局中的TextView,使其达到逐字显示的效果。
问题
拿到流式数据后,就封装数据,并刷新RecyclerView,但是发现无法实现既定效果。
解决方案
使用队列LinkedList保存流式返回的所有数据,然后利用递归的方式,逐个从队列里取数据并刷新RecyclerView
//一些核心代码
// 缓存收到的字符
private Queue<String> charQueue = new LinkedList<>();
private List<Message> messageList = new ArrayList<>();
private void displayCharacter() {
nextChar = charQueue.poll();
if (nextChar == null) {
//完成显示
return;
}
// 显示字符
if (messageList.isEmpty()) {
messageList.add(new Message(nextChar));
adapter.notifyDataSetChanged();
} else {
// 更新最后一条消息
Message lastMessage = messageList.get(messageList.size() - 1);
lastMessage.appendContent(nextChar);
// 使用增量更新通知适配器
adapter.notifyItemChanged(messageList.size() - 1, "typing");
}
// 滚动到底部,但不使用平滑滚动以避免干扰打字动画
recyclerView.scrollToPosition(messageList.size() - 1);
// 计算下一个字符的延迟
int delay = calculateDelay(nextChar);
// 安排显示下一个字符
handler.postDelayed(this::displayNextCharacter, delay);
}
后记:如果流式数据返回内容过多,等数据返回完以后再进行展示,体验效果会比较差,后来尝试了一下,在非主线程保存数据到阻塞队列里,同时开启一个单线程取数据,然后交给主线程去刷新列表进行展示,最终效果还不错