tencent cloud

实时音视频

动态与公告
产品动态
产品近期公告
关于 TRTC Live 正式上线的公告
关于TRTC Conference 正式版上线的公告
Conference 商业化版本即将推出
关于多人音视频 Conference 开启内测公告
关于音视频通话 Call 正式版上线的公告
关于腾讯云音视频终端 SDK 播放升级及新增授权校验的公告
关于 TRTC 应用订阅套餐服务上线的相关说明
产品简介
产品概述
基本概念
产品功能
产品优势
应用场景
性能数据
购买指南
计费概述
免费时长说明
月订阅
现收现付
TRTC 逾期与暂停政策
常见问题解答
退款说明
新手指引
Demo 体验
视频通话 SDK
组件介绍
开通服务
跑通 Demo
快速接入
离线唤醒
会话聊天
云端录制
AI 降噪
界面定制
Chat 集成通话能力
更多特性
无 UI 集成
服务端 API
客户端 API
解决方案
错误码表
发布日志
常见问题
视频会议 SDK
组件介绍(TUIRoomKit)
开通服务(TUIRoomKit)
跑通 Demo(TUIRoomKit)
快速接入(TUIRoomKit)
屏幕共享(TUIRoomKit)
预定会议(TUIRoomKit)
会中呼叫(TUIRoomKit)
界面定制(TUIRoomKit)
虚拟背景(TUIRoomKit)
会议控制(TUIRoomKit)
云端录制(TUIRoomKit)
AI 降噪(TUIRoomKit)
会中聊天(TUIRoomKit)
机器人推流(TUIRoomKit)
更多特性(TUIRoomKit)
客户端 API(TUIRoomKit)
服务端 API(TUIRoomKit)
常见问题(TUIRoomKit)
错误码 (TUIRoomKit)
SDK更新日志(TUIRoomKit)
直播与语聊 SDK
Live 视频直播计费说明
组件介绍
开通服务(TUILiveKit)
跑通 Demo
无 UI 集成
UI 自定义
直播监播
视频直播
语聊房
高级功能
客户端 API
服务端 API
错误码
发布日志
常见问题
RTC Engine
开通服务
SDK 下载
API-Example
接入指引
API-参考手册
高级功能
AI 集成
概述
MCP 配置
Skills 配置
集成指南
常见问题
RTC RESTFUL API
History
Introduction
API Category
Room Management APIs
Stream mixing and relay APIs
On-cloud recording APIs
Data Monitoring APIs
Pull stream Relay Related interface
Web Record APIs
AI Service APIs
Cloud Slicing APIs
Cloud Moderation APIs
Making API Requests
Call Quality Monitoring APIs
Usage Statistics APIs
Data Types
Appendix
Error Codes
控制台指南
应用管理
套餐包管理
用量统计
监控仪表盘
开发辅助
解决方案
实时合唱
常见问题
迁移指南
计费相关
功能相关
UserSig 相关
应对防火墙限制相关
缩减安装包体积相关
Andriod 与 iOS 相关
Web 端相关
Flutter 相关
Electron 相关
TRTCCalling Web 相关
音视频质量相关
其他问题
旧版文档
RTC RoomEngine SDK(旧)
集成 TUIRoom (Web)
集成 TUIRoom (Android)
集成 TUIRoom (iOS)
集成 TUIRoom (Flutter)
集成 TUIRoom (Electron)
TUIRoom API 查询
实现云端录制与回放(旧)
监控仪表盘计费(旧)
协议与策略
安全合规认证
安全白皮书
信息安全说明
服务等级协议
苹果隐私策略:PrivacyInfo.xcprivacy
TRTC 政策
隐私协议
数据处理和安全协议
词汇表

弹幕(Android)

PDF
聚焦模式
字号
最后更新时间: 2025-12-04 15:09:54
本篇文档旨在指导 Android 开发者如何使用 AtomicXCore 框架中的 BarrageStore 模块,为您的直播应用快速集成功能丰富、性能卓越的弹幕系统。


核心功能

BarrageStore 为您的直播应用提供了一套完整的弹幕解决方案,核心功能包括:
接收并展示直播间弹幕消息。
发送文本弹幕与观众互动。
发送自定义业务弹幕,以支持礼物、点赞等复杂场景。
在本地消息列表中插入系统提示(例如,"欢迎 XX 进入直播间")。

核心概念

核心概念
类型
核心职责与描述
Barrage
data class
代表一条弹幕消息的数据模型。它包含了发送者信息 (sender)、消息内容 (textContentdata)、消息类型 (messageType) 等所有关键信息。
data class
代表弹幕模块的当前状态。其核心属性 messageList 是一个StateFlow,按时间顺序存储了当前直播间的所有弹幕消息,是UI渲染的数据源。
abstract class
这是与弹幕功能交互的核心管理类。通过它,您可以发送消息 (sendTextMessage, sendCustomMessage),并通过订阅其 state 属性来接收和监听所有弹幕消息的更新。

实现步骤

步骤1:组件集成

视频直播:请参考 快速接入 集成 AtomicXCore,完成接入。
语聊房:请参考 快速接入 集成 AtomicXCore,完成接入。

步骤2:初始化并监听弹幕

获取一个与当前直播间 liveId 绑定的 BarrageStore 实例,并设置一个订阅者来实时接收最新的全量弹幕消息列表。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import io.trtc.tuikit.atomicxcore.api.barrage.Barrage
import io.trtc.tuikit.atomicxcore.api.barrage.BarrageStore

class BarrageManager(
private val liveId: String
) {
private val barrageStore: BarrageStore = BarrageStore.create(liveId)
private val scope = CoroutineScope(Dispatchers.Main)
// 对外暴露【全量】消息列表的Flow,方便UI层订阅
private val _messagesFlow = MutableStateFlow<List<Barrage>>(emptyList())
val messagesFlow: StateFlow<List<Barrage>> = _messagesFlow.asStateFlow()
init {
// 初始化后立即开始监听弹幕消息
subscribeToBarrageUpdates()
}

private fun subscribeToBarrageUpdates() {
scope.launch {
barrageStore.barrageState.messageList
.collect { messageList ->
// 当 messageList 更新时,通过 Flow 将新列表传递给UI层
// 关键点:这里接收到的是包含所有历史消息的【完整列表】
_messagesFlow.value = messageList
}
}
}
}

步骤3:发送文本弹幕

调用 sendTextMessage 方法向直播间内的所有用户广播一条纯文本消息。
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
import io.trtc.tuikit.atomicxcore.api.barrage.BarrageStore

class BarrageManager(
private val liveId: String
) {
private val barrageStore: BarrageStore = BarrageStore.create(liveId)

// 发送一条文本弹幕
fun sendTextMessage(text: String) {
// 建议:增加非空校验,避免发送无效消息
if (text.isEmpty()) {
return
}
// 调用核心API发送消息
barrageStore.sendTextMessage(
text,
mapOf(
"custom key" to "custom value",
),
object : CompletionHandler {
override fun onSuccess() {
println("文本弹幕 '$text' 发送成功")
}

override fun onFailure(code: Int, desc: String) {
println("文本弹幕发送失败: $desc")
}
}
)
}
}


接口参数

参数
类型
描述
text
String?
要发送的文本内容。
extensionInfo
Map<String, String>?
附加的扩展信息,可用于业务自定义。
completion
CompletionHandler?
发送完成后的回调,包含成功或失败的结果。

步骤4:发送自定义弹幕

发送一条包含自定义业务逻辑的消息,例如礼物、点赞或游戏化互动指令。这条消息的内容格式由业务层自行定义,接收端需要根据 businessIddata 自行解析和处理。
class BarrageManager(
private val liveId: String
) {
// 发送一条自定义弹幕,例如用于发送礼物
fun sendGiftMessage(giftId: String, giftCount: Int) {
// 1. 定义一个能识别业务的ID
val businessId = "live_gift"

// 2. 将业务数据编码为 JSON 字符串
val giftData = mapOf(
"gift_id" to giftId,
"gift_count" to giftCount
)

val jsonString = try {
// 使用 Gson 或其他 JSON 库进行序列化
// 这里假设使用 Gson
Gson().toJson(giftData)
} catch (e: Exception) {
return
}

// 3. 调用核心API发送自定义消息
barrageStore.sendCustomMessage(
businessId,
jsonString,
object : CompletionHandler {
override fun onSuccess() {
println("礼物消息(自定义弹幕)发送成功")
}
override fun onFailure(code: Int, desc: String) {
println("礼物消息发送失败: $desc")
}
}
)
}
}

接口参数

参数
类型
描述
businessId
String
业务唯一标识符,例如 "live_gift",用于接收端区分不同的自定义消息。
data
String
业务数据,通常为 JSON 格式的字符串。
completion
CompletionHandler?
发送完成后的回调。

步骤5:在本地插入提示消息

在当前用户的消息列表中插入一条本地消息,这条消息不会被发送到直播间的其他用户。这非常适合用来显示系统欢迎、警告或操作提示等信息。
class BarrageManager(
private val liveId: String
) {
// 在本地消息列表中插入一条欢迎提示
fun showWelcomeMessage(user: LiveUserInfo) {
// 1. 创建一条 Barrage 消息
val welcomeTip = Barrage(
liveID = liveId,
messageType = BarrageType.TEXT, // 可以复用 text 类型来显示
textContent = "欢迎 ${user.userName} 进入直播间!",
sender = LiveUserInfo() // sender 可以留空或设置为一个系统用户的标识
)

// 2. 调用API将其插入本地列表
barrageStore.appendLocalTip(welcomeTip)
}
}

接口参数

参数
类型
描述
message
Barrage
要在本地插入的消息对象。SDK 会将此消息对象追加到 BarrageState 的 messageList 中。

步骤6:管理用户发言(禁言与解禁)

作为主播或管理员,您可以对直播间内的用户发言权限进行管理,维护健康的社区氛围。

禁止/解禁单个用户发言

通过 LiveAudienceStore 中的 disableSendMessage 接口来实现对指定用户的禁言或解禁。此状态会被持久化,即使用户重新进入直播间,禁言状态依然有效。
import io.trtc.tuikit.atomicxcore.api.*
import io.trtc.tuikit.atomicxcore.api.live.LiveAudienceStore

// 1. 获取与当前直播间绑定的 LiveAudienceStore 实例
val audienceStore = LiveAudienceStore.create(liveId)

// 2. 定义要操作的用户ID和禁言状态
val userIdToMute = "user_id_to_be_muted"
val shouldDisable = true // true为禁言, false为解禁

// 3. 调用接口执行操作
audienceStore.disableSendMessage(
userIdToMute,
shouldDisable,
object : CompletionHandler {
override fun onSuccess() {
println("${if (shouldDisable) "禁言" else "解禁"}用户 $userIdToMute 成功")
}

override fun onFailure(code: Int, desc: String) {
println("操作失败: $desc")
}
}
)

开启/关闭全体禁言

要对直播间内所有用户(通常不包括主播自己)进行禁言,您需要通过 LiveListStore 更新直播间信息来实现。
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
import io.trtc.tuikit.atomicxcore.api.live.LiveInfo
import io.trtc.tuikit.atomicxcore.api.live.LiveListStore

// 1. 获取 LiveListStore 单例
val liveListStore = LiveListStore.shared()

// 2. 获取当前直播间信息,并修改全体禁言状态
val currentLiveInfo = liveListStore.liveState.currentLive.value.copy(
isMessageDisable = true // true为全体禁言, false为关闭
)

// 3. 调用更新接口,并指定修改的标志位
liveListStore.updateLiveInfo(
currentLiveInfo,
listOf(LiveInfo.ModifyFlag.IS_MESSAGE_DISABLE),
object : CompletionHandler {
override fun onSuccess() {
println("全体禁言状态更新成功")
}

override fun onFailure(code: Int, desc: String) {
println("操作失败: $desc")
}
}
)

功能进阶:高并发场景下的性能优化

当您使用 BarrageStore 构建弹幕功能后,本章将指导您如何处理更复杂的业务场景,确保它能在真实、复杂的高并发直播场景下,依然为用户提供流畅、稳定的体验。本章将围绕三个核心业务场景,为您提供明确的优化方案和代码示例。

场景一:应对热门直播间的"弹幕风暴"

场景描述

在一场热门活动中,直播间涌入大量观众,弹幕以每秒数十条的频率刷新。

技术挑战

SDK会以极高频率返回完整的弹幕列表。如果每次都调用 adapter.notifyDataSetChanged(),主线程会被密集的 UI 布局和渲染操作阻塞,导致界面卡顿。

优化方案:批处理与流量削峰 (Batch Processing & Debouncing)

不必响应每一次的数据更新,而是设定一个时间阈值(例如300毫秒)。只在距离上次UI刷新超过这个阈值后,才执行下一次刷新操作。这能将每秒数十次的 notifyDataSetChanged() 调用,降低到每秒3-4次,极大提升流畅度。

代码示例

创建一个 BarrageUIManager 类,它内置一个缓冲区和一个定时器,专门负责将数据批量更新到 RecyclerView
import android.os.Handler
import androidx.recyclerview.widget.RecyclerView
import io.trtc.tuikit.atomicxcore.api.barrage.Barrage

private const val UPDATE_DURATION_MS = 300L

class BarrageUIManager() {
private var timestampOnLastUpdate = 0L

private var dataSource: ArrayList<Barrage> = ArrayList()
private val updateViewTask = Runnable { notifyDataSetChanged() }
private val handler = Handler()
private val adapter = BarrageAdapter(dataSource)

// 外部高频调用此方法,传入最新的全量列表
fun update(newList: List<Barrage>) {
handler.removeCallbacks(updateViewTask)
dataSource.clear()
dataSource.addAll(newList)
// 刷新频率小于 0.3 秒,不做刷新
if (System.currentTimeMillis() - timestampOnLastUpdate < UPDATE_DURATION_MS) {
handler.postDelayed(updateViewTask, UPDATE_DURATION_MS)
return
}
}

private fun notifyDataSetChanged() {
adapter.notifyDataSetChanged()
timestampOnLastUpdate = System.currentTimeMillis()
}
}

class BarrageAdapter(dataSource: ArrayList<Barrage>): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
//这里实现adapter能力
}

场景二:保障长时间直播的内存稳定性

场景描述

您的应用需要支持数小时乃至全天候的"不间断直播",例如游戏直播或慢直播。在此期间,App 必须保持稳定运行,不能因为长时间运行而意外退出。

技术挑战

SDK 返回的全量 messageList 会在长时间直播中无限增长,即使 UI 层做了节流,数据层持有的这个巨大数组也会持续侵占内存,最终导致应用闪退。

优化方案:固定容量的循环数组 (Circular Buffer)

只让您自己的数据源(DataSource)持有有限数量的消息。无论 SDK 返回的全量列表有多大,您的应用只截取其中最新的部分用于显示。

代码示例

在接收到 SDK 的全量列表后,只取最新的500条(或您定义的其他数量)来更新 UI。
class BarrageUIManager(
private val recyclerView: RecyclerView
) {
private val capacity: Int = 500 // 客户端只保留最新的500条消息
// ...(其他代码同上)...

private fun refreshUIIfNeeded() {
val fullList = this.latestMessageList ?: return
val adapter = recyclerView.adapter ?: return
this.latestMessageList = null

// 关键点:截取最新的N条消息
val cappedList = fullList.takeLast(capacity)
dataSource.clear()
dataSource.addAll(cappedList)
adapter.notifyDataSetChanged()
}
}

场景三:渲染包含用户等级、徽章的复杂弹幕样式

场景描述

为了增强直播氛围和付费用户荣誉感,弹幕需要展示丰富的视觉元素,例如混排用户名、用户等级图标、粉丝徽章和消息内容。

技术挑战

渲染包含多图文、自定义字体或复杂布局的视图,比渲染纯文本耗时更长。在列表中高频渲染这些复杂视图,会加重主线程的计算压力,导致列表滚动时出现卡顿。

优化方案:异步绘制 (Asynchronous Drawing)

将视图内容的绘制过程从主线程剥离,放到后台线程去完成。主线程只负责最终的"贴图"操作,即显示已经绘制好的位图。这极大地减轻了主线程的计算压力。

代码示例

在您的自定义 RecyclerView.ViewHolder 中,通过使用 AsyncLayoutInflater 或预加载机制,来指示系统尽可能地在后台线程完成绘制任务。
import android.view.LayoutInflater
import androidx.asynclayoutinflater.view.AsyncLayoutInflater
import androidx.recyclerview.widget.RecyclerView

// 在你的自定义弹幕ViewHolder中
class BarrageViewHolder(
itemView: View
) : RecyclerView.ViewHolder(itemView) {

// ... (TextView, ImageView等子视图的声明)

companion object {
fun create(parent: ViewGroup): BarrageViewHolder {
// 使用异步布局加载器来减少主线程阻塞
val inflater = AsyncLayoutInflater(parent.context)
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_barrage, parent, false)
return BarrageViewHolder(view)
}
}

fun bind(viewModel: BarrageViewModel) {
// 在这里设置你的TextView文本、ImageView图片等
// 由于使用了异步布局加载,这些内容的最终渲染会尽量在后台完成
}

// 追求极致性能的进阶方案:完全手动绘制
// 如果需要更精细的控制,可以使用Canvas手动绘制文本和图片
// 结合后台线程生成Bitmap,然后在主线程的onDraw方法中绘制它,可以实现完全的异步渲染
}

API 文档

关于 BarrageStore 及其相关类的所有公开接口、属性和方法的详细信息,请参阅随 AtomicXCore 框架的官方 API 文档。

常见问题

除了基础的文本弹幕,我们还希望实现"彩色弹幕"、"礼物弹幕"等更丰富的样式,该如何实现?

这是通过自定义消息 sendCustomMessage 来实现的。
实现思路
1. 定义数据结构: 与您的客户端和服务器团队共同定义好自定义消息的 JSON 结构。例如,一条彩色弹幕可以这样定义:
{ "type": "colored_text", "text": "这是一条彩色弹幕!", "color": "#FF5733" }
2. 发送端: 在发送时,将这个 JSON 结构转换为字符串,并通过 sendCustomMessagedata 参数发送出去。businessID 可以设置为一个能代表您业务的唯一标识,例如 "barrage_style_v1"。
3. 接收端: 在接收到弹幕消息后,检查其 messageType 是否为 BarrageType.CUSTOM 以及 businessID 是否匹配。如果匹配,则解析 data 字符串(通常是解析 JSON),根据解析出的数据(例如 color、text)来渲染您的自定义UI样式。

我在不同的类、不同的文件中都调用了 BarrageStore.create(liveID = "some_id"),这会创建出多个实例导致混乱吗?

完全不会。AtomicXCore 内部机制会确保只要您传入的 liveID 相同,获取到的永远是同一个与该直播间绑定的 BarrageStore 实例。您可以在需要的地方随用随取,无需手动管理单例。

为什么我调用了 sendTextMessage,但是在消息列表中看不到我发送的消息?

请按以下步骤排查:
1. 检查 completion 回调:sendTextMessage 方法有一个完成回调。请检查回调返回的结果是成功还是失败。如果失败,错误信息会明确指出问题所在(例如"您已被禁言"、"网络错误"等)。
2. 确认订阅时机:确保您对 barrageStore.barrageState.messageList 的订阅发生在该 liveID 对应的直播开始之后。如果在加入直播房间之前就开始监听,可能会错过部分消息。
3. 检查 liveID:确认您在创建 BarrageStore 实例、加入直播房间、以及发送消息时使用的 liveID 完全一致,包括大小写。
4. 网络问题:检查设备当前的网络连接是否正常。消息发送依赖于网络。

新观众进入直播间时,如何让他们看到加入前的历史弹幕消息?

AtomicXCore 支持拉取历史弹幕消息,但这需要您在服务端控制台进行一项简单的配置。配置完成后,SDK会自动处理后续的一切,您无需编写额外的代码。
步骤1:在 IM 控制台进行配置
1. 登录您的 Chat 控制台
2. 在左侧导航栏,按照路径消息服务 Chat > 功能配置 > 群组配置 > 群功能配置 > 直播群新成员查看入群前消息量配置进行导航。

3. 修改"新成员可查看最近消息数",最大支持 50 条。
步骤2:客户端无感获取
完成上述配置后,您的客户端代码无需做任何改动
当新用户加入直播间时,AtomicXCore 的底层会自动拉取您配置的历史消息数量。这些历史消息会和实时消息一样,通过您已实现的 BarrageStore.barrageState.messageList 订阅通道推送给您的 UI 层。您的应用会像接收实时弹幕一样,自然地接收并展示这些历史弹幕。

帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈