HarmonyOS鸿蒙Next中emitter发送的数据为什么会被转成object

HarmonyOS鸿蒙Next中emitter发送的数据为什么会被转成object 在音视频通话场景下,通过emitter将MediaTrack进行分发,接受者收到后将Mediatrack绑定到Xcomponent上渲染,但是一直报错,排查后发现是因为emitter订阅函数中接收到的对象是object类型,由于Mediatrack中绑定了Napi层的一些native 指针,所以对象变了后里面的所有指针都变了,导致渲染失败,请问这个问题为什么这么设计?为什么分发的不是原对象呢?也不需要你进行存储为什么还要序列号呢?

4 回复

你好, EventData 传递的数据类型是 { [key: string]: any } ,需要多包一层,传递的才是原对象。

emitter.emit('EventId', {
  data: {
    'value': new MediaTrack()
  }
})


emitter.on('EventId', (e: emitter.EventData) => {
  const data = e.data as Record<string,Object>
  const value = data['value'] as MediaTrack
})

也可以使用 GenericEventData,发送事件时传递的泛型数据。

const eventData: emitter.GenericEventData<MediaTrack> = {
    data: new MediaTrack()
};
emitter.emit("eventId", eventData);

emitter.on("eventId", (eventData: emitter.GenericEventData<MediaTrack>): void => {
  if (eventData?.data instanceof MediaTrack) {
    const value = eventData?.data
  }
});

更多关于HarmonyOS鸿蒙Next中emitter发送的数据为什么会被转成object的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


建议将需要发送的数据放在一个单例中,这样所有位置都可以访问到原对象内容。

emitter 发送个通知string内容就可以了。

通知和数据相分离!

在HarmonyOS Next中,emitter发送的数据会被自动封装为对象,这是系统事件机制的设计。事件数据通过EventData对象进行传递,以确保数据的结构化和类型安全。这种封装允许事件携带多个字段,并支持统一的数据处理接口。开发者需要按照EventData的格式来发送和接收事件数据。

在HarmonyOS Next中,emitter作为事件中心进行跨线程/跨组件通信时,会对传输的数据进行序列化和反序列化处理,这是出于架构设计的必要考量。

核心原因在于进程隔离与线程安全。HarmonyOS Next应用采用多进程模型,UI、媒体等常运行于独立进程。MediaTrack等对象可能包含Native层指针或句柄,这些资源与创建它们的进程强绑定,无法直接跨进程传递。Emitter的通信机制本质上是跨进程通信(IPC)或跨线程通信的一种抽象。

当您通过emitter发送MediaTrack时,系统并非直接传递原始对象,而是会:

  1. 提取对象的可序列化描述信息(如标识符、类型、状态等元数据),生成一个普通的JavaScript对象(即您收到的object类型数据)。
  2. 在接收侧,根据这些描述信息,在本地重新创建或查找对应的Native资源句柄

您遇到的渲染失败,正是因为接收侧获取到的是一个描述性对象,而非原对象所持有的Native指针。正确的做法不是在接收侧直接使用该对象进行渲染,而是:

  • 使用该描述对象中的关键标识(如trackId),在接收侧的上下文中,通过对应的ArkTS/NAPI接口重新获取或关联到真正的MediaTrack实例
  • 例如,在媒体子系统或XComponent的绑定接口中,通常需要传入从emitter收到的对象中的某个ID,来关联到正确的媒体轨道。

这不是一个“问题”,而是分布式架构下的安全设计。它确保了:

  • 稳定性:避免直接传递内存指针导致的进程崩溃。
  • 安全性:防止进程间非法访问内存。
  • 松耦合:通信双方仅依赖数据契约,而非具体实现。

解决方案:请检查接收侧代码,确保使用emitter传递过来的描述性对象中的必要标识符,调用正确的HarmonyOS API(如AVSessionXComponent的相关方法)来获取当前进程内有效的、可操作的媒体资源对象,再进行渲染绑定。

回到顶部