HarmonyOS 鸿蒙Next 关于eventhub传入同样名称函数时,只有先传入的起效的记录
本文没有结论,完全水字数的。
本来想去提个问题的,但是想了下,估计短期内无法满足,所以暂且作为一个eventhub学习记录。如果有大佬指点,先在这谢过。
学习目标:实现类的实例根据实际情况,自行订阅、取消、触发某个事件。
目标场景,有一个类A,A有一个成员a(不是static),有一个A类的对象池KK,KK中的A的实例对会按需渲染,至于哪些实例对象会渲染,会实时动态更新。某个实例的a发生变化,会通知其他实例中,与a有关的成员进行更新,起到数据同步的作用。
最初想法:在A类中,设置一个事件触发、订阅、取消的专用函数,以及一个回调执行函数。这样,当A创建实例时,实例就会有一个自己的事件回调,用来更新实例内部自有的变量。就不用每个变量单独创建一个事件触发、订阅、取消的函数,节省重复代码。A的实例在窗口显示时,需要订阅特定事件,在隐藏或者卸载UI组件时,需要取消本实例的事件订阅,其他任然显示的实例,不会取消事件。
实际场景,在开发中,因为回调函数是实例自动生成的,所以导致这个每个实例在订阅事件时,传入的函数名是一样的。经过测试,当传入已有同名的回调函数时,只有最先传入的那个会起效果。
随之也出现另一个问题,因为时更改实例内部的成员(可能是私有的),在回调函数中,用的是this来获取数据。然后导致程序运行到事件回调时崩溃,如果this在hilog中打印,这条打印语句也不会执行。
实例代码如下:
import { hilog } from "@kit.PerformanceAnalysisKit";
import { common } from "@kit.AbilityKit";
import zifu from "../../00JIYOUgongneng/ZIFUziyuan/Zifu202411100337";
import TONGYONG from "../../00JIYOUgongneng/QITAgongneng/TONGYONG";
@Entry
@Component
struct CSeventhubFankui {
@State message: string = 'Hello World';
build() {
RelativeContainer() {
Text(this.message)
.id('CSeventhubFankuiHelloWorld')
.fontSize(50)
.fontWeight(FontWeight.Bold)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
}
.height('100%')
.width('100%')
}
}
@Builder
export function CSEventhubNAV(){
CSgongneng2()
}
@Component
export struct CSgongneng2{
private daohangqi:NavPathStack = new NavPathStack();
private cc:common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
private changguidingyue:string = '常规订阅事件';
private changguiCishu:number = 0;
//类实例对象各自订阅
@State ceshiDuixiang1:cs = new cs(this.cc,'一');
@State ceshiDuixiang2:cs = new cs(this.cc,'二');
//回调参数对象
@State canshuDuixiang:cs = new cs(this.cc,'参数对象');
@State jieguo:string = '无结果'
@State changguiJieguo:number = 0;
aboutToAppear(): void {
}
aboutToDisappear(): void {
}
build() {
NavDestination(){
Column(){
Scroll(){
Column({space:5}){
Column(){
Text('按照一般的方式去正常订阅,功能都正常,并且同一事件可挂载多个回调。')
.width('100%')
.textAlign(TextAlign.Start)
.backgroundColor('#ff1c92f6')
.height(150)
Row(){
Text('测试对象结果显示:')
Text(`${this.changguiJieguo}`)
.layoutWeight(1)
.backgroundColor('#ff93b2f6')
}
.width('100%')
.justifyContent(FlexAlign.Start)
.height(50)
Row(){
Button('订阅')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.cc.eventHub.on(this.changguidingyue,() => {
this.changguiJieguo++;
this.changguiCishu++;
hilog.info(77,this.changguidingyue,'执行次数'+this.changguiCishu)
})
})
Button('触发')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.cc.eventHub.emit(this.changguidingyue)
})
Button('取消')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.cc.eventHub.off(this.changguidingyue)
})
Button('重置次数')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.changguiCishu = 0;
})
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
.width('100%')
Column(){
Text('通过直接使用类已实现的事件专用函数进行订阅,使用无参回调函数,函数内部通过this获取所需数据。在回调时无法获取通过this这种方式引用的数据。')
.width('100%')
.textAlign(TextAlign.Start)
.backgroundColor('#ff1c92f6')
.height(150)
Row(){
Text('测试对象结果显示:')
Text(this.jieguo)
.layoutWeight(1)
.backgroundColor('#ff93b2f6')
}
.width('100%')
.justifyContent(FlexAlign.Start)
.height(50)
Row(){
Button('订阅')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.ceshiDuixiang1.dingyueWucan();
})
Button('触发')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.ceshiDuixiang1.dingyuechufa(this.ceshiDuixiang1);
this.jieguo = '' + this.ceshiDuixiang1.shuju
})
Button('取消')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.ceshiDuixiang1.dingyuequxiaoWucan();
})
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
.width('100%')
Column(){
Text('通过直接使用类已实现的事件专用函数进行订阅,使用有参回调函数,函数内部通过参数对象获取所需数据。函数对象获取的数据会输出,无法获取通过this这种方式引用的数据。')
.width('100%')
.textAlign(TextAlign.Start)
.backgroundColor('#ff1c92f6')
Row(){
Text('测试对象结果显示:')
Text(this.jieguo)
.layoutWeight(1)
.backgroundColor('#ff93b2f6')
}
.width('100%')
.justifyContent(FlexAlign.Start)
.height(50)
Row(){
Button('订阅')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.ceshiDuixiang1.dingyueYoucan();
})
Button('触发')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.ceshiDuixiang1.dingyuechufa(this.ceshiDuixiang1);
this.jieguo = '' + this.ceshiDuixiang1.shuju
})
Button('取消')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.ceshiDuixiang1.dingyuequxiaoYoucan();
})
}
.width('100%')
.height(50)
}
.width('100%')
Column(){
Text('如果同一个事件下,一个类的两个实例的函数(两个函数名一样)作为回调函数,会被当成一个,即eventhub中,只会有一个名为zhixingYoucan(),不是一个实例一个')
.width('100%')
.textAlign(TextAlign.Start)
.backgroundColor('#ff1c92f6')
Row(){
Text('测试对象结果显示:')
Text(this.jieguo)
.layoutWeight(1)
.backgroundColor('#ff93b2f6')
}
.width('100%')
.justifyContent(FlexAlign.Start)
.height(50)
Row(){
Button('第一个对象订阅')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.ceshiDuixiang1.dingyueYoucan();
})
Button('第二个对象订阅')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.ceshiDuixiang2.dingyueYoucan();
})
Button('触发')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.cc.eventHub.emit(this.ceshiDuixiang1.shijianming,this.ceshiDuixiang1);
this.jieguo = this.ceshiDuixiang1.shuju + ';' + this.ceshiDuixiang2.shuju;
})
Button('取消')
.height(50)
.layoutWeight(1)
.onClick(() => {
this.cc.eventHub.off(this.ceshiDuixiang1.shijianming);
})
}
.width('100%')
.height(50)
}
.width('100%')
}
.layoutWeight(1)
.width('100%')
.justifyContent(FlexAlign.Start)
}
.layoutWeight(1)
.width('100%')
.align(Alignment.Start)
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Start)
}
.title('Eventhub功能测试页')
.height('100%')
.width('100%')
.title(zifu.Yemianming.gongnengceshi.name)
.onReady((e:NavDestinationContext) => {
if (e?.pathStack) {
this.daohangqi = e.pathStack;
}
})
}
}
export class cs{
readonly shijianming:string = '测试事件';
readonly biaoqian:string = '测试类'
readonly cc:common.UIAbilityContext;
shuju:number = 0;//回调函数需要改变的数据,会在顶部text显示
constructor(c:common.UIAbilityContext,m?:string) {
this.cc = c;
this.biaoqian = '实例' + TONGYONG.shijian() + m;
}
private zhixingWucan(){
this.shuju++;
hilog.info(1,this.biaoqian,this.shuju+'this数据输出'+ TONGYONG.shijian());//不会被执行
hilog.info(1,'事件执行回调','无参回调执行,内部通过this获取数据')
}
private zhixingYoucan(dx:cs){
this.shuju++;
dx.shuju++;
hilog.info(1,this.biaoqian,this.shuju+'this数据输出'+ TONGYONG.shijian());//不会被执行
hilog.info(1,dx.biaoqian,dx.shuju+'参数对象,数据输出'+ TONGYONG.shijian());
hilog.info(1,'事件执行回调','有参回调执行,内部通过this获取数据')
}
//类内部事件订阅专用函数,无参回调函数,通过this获取数据
dingyueWucan(){
this.cc.eventHub.on(this.shijianming,this.zhixingWucan)
hilog.info(1,this.biaoqian,'订阅事件,无参回调'+ TONGYONG.shijian()+'无参回调函数')
}
//类内部事件订阅专用函数,有参回调函数,通过参数对象获取数据
dingyueYoucan(){
this.cc.eventHub.on(this.shijianming,this.zhixingYoucan)
hilog.info(1,this.biaoqian,'订阅事件,有参回调'+ TONGYONG.shijian()+'有参回调函数')
}
dingyuechufa(dx:cs){
this.cc.eventHub.emit(this.shijianming,dx)
hilog.info(1,this.biaoqian,'触发事件'+ TONGYONG.shijian())
}
dingyuequxiaoWucan(){
this.cc.eventHub.off(this.shijianming,this.zhixingWucan)
hilog.info(1,this.biaoqian,'取消事件'+ TONGYONG.shijian())
}
dingyuequxiaoYoucan(){
this.cc.eventHub.off(this.shijianming,this.zhixingYoucan)
hilog.info(1,this.biaoqian,'取消事件'+ TONGYONG.shijian())
}
}
// export class cs2{
// readonly biaoqian:string = '回调参数对象'
// jishu:number = 0;//回调函数需要改变的数据,会在顶部text显示
// constructor() {
// }
//
// huidiaozhixing(){
// this.jishu++;
// hilog.info(2,this.biaoqian,'参数对象执行,当前计数' + this.jishu);
// }
// }
因为考虑到性能和后期扩展,还是想使用实例的方式去生成回调函数,后来使用了其他方式,虽然满足了后面的扩展,但是增加了性能消耗、事件管理难度。
今天测试了半天,本来以为能找到更好的方法实现。结果发现,除了改底层,或者自己重新实现,其他方式都差不多。要么开发繁琐,需要在很多个地方增加代码;要么无法所有实例正常获取;要么就是无法回调。所以先随便找了种方式做着。
针对HarmonyOS鸿蒙Next中EventHub传入同样名称函数时,只有先传入的起效的问题,这通常是由于事件注册机制导致的。在EventHub中,如果多个回调函数使用相同的名称或标识符进行注册,系统可能只会保留第一个注册的回调函数,或者后续注册的回调函数会覆盖先前的。
为了解决这个问题,你可以尝试以下方法:
- 确保每个事件回调函数具有唯一的标识符或名称,避免使用相同的名称进行注册。
- 如果确实需要使用相同的回调函数处理不同的事件,可以考虑在回调函数内部根据事件类型或参数进行区分处理。
- 检查事件注册的逻辑,确保没有重复注册或覆盖注册的情况。
此外,还需要注意EventHub的使用规范,如确保事件ID的一致性、检查上下文匹配等,以避免其他潜在的问题。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html