HarmonyOS APP事件驱动大揭秘

事件驱动:CommonEvent与EventHandler

从"轮询"到"通知",事件驱动让系统更高效

一、背景与动机:为什么需要事件驱动?

1.1 轮询 vs 事件驱动

假设你要等一个快递,有两种方式:

轮询方式:每隔5分钟给快递员打个电话问"到了吗?"

  • 你很累,快递员也很烦
  • 大部分电话都是无效的

事件驱动方式:告诉快递员"到了给我打电话"

  • 你该干嘛干嘛
  • 快递到了才通知你
typescript 复制代码
// ❌ 轮询方式:浪费资源
while (true) {
    if (isPackageArrived()) {
        handlePackage()
        break
    }
    sleep(5000)  // 每5秒检查一次
}

// ✅ 事件驱动:高效响应
registerPackageListener((package) => {
    handlePackage(package)  // 快递到了才执行
})

1.2 鸿蒙的事件体系

鸿蒙提供了完整的事件驱动机制:

组件 作用 适用场景
CommonEvent 系统级事件总线 跨进程、系统事件
EventHandler 线程级事件队列 线程间通信、延时任务
Emitter 进程内事件发射器 组件间通信
graph TB subgraph System[&#34;系统级&#34;] A[CommonEvent<br/>跨进程事件总线] end subgraph Process[&#34;进程级&#34;] B[Emitter<br/>进程内事件] C[EventHandler<br/>线程事件队列] end subgraph Thread[&#34;线程级&#34;] D[主线程EventHandler] E[工作线程EventHandler] end A --> B B --> C C --> D C --> E classDef primary fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px classDef info fill:#e3f2fd,stroke:#1565c0,stroke-width:2px classDef warning fill:#fff3e0,stroke:#e65100,stroke-width:2px class A primary class B,C info class D,E warning

1.3 CommonEvent vs EventHandler

很多开发者分不清这两个:

  • CommonEvent:系统级事件总线,支持跨进程发布和订阅

    • 例:电量变化、网络状态变化、屏幕亮灭
    • 特点:全局可见、跨进程、需要权限
  • EventHandler:线程级事件队列,用于线程间通信

    • 例:工作线程通知UI线程更新界面
    • 特点:线程私有、高性能、支持延时
typescript 复制代码
// CommonEvent:订阅系统电量变化
CommonEvent.subscribe({
    events: ['android.intent.action.BATTERY_CHANGED']
}, (err, data) => {
    console.log(`电量: ${data.data}%`)
})

// EventHandler:工作线程通知UI
class MyHandler extends EventHandler {
    processEvent(eventId: number, param: unknown) {
        if (eventId === 1) {
            // 在主线程执行UI更新
            updateUI(param)
        }
    }
}

二、核心原理:事件驱动机制

2.1 CommonEvent架构

graph TB subgraph ProcessA[&#34;进程A(发布者)&#34;] A1[业务代码] A2[CommonEvent.publish] end subgraph System[&#34;系统服务&#34;] B1[CommonEventManager<br/>事件管理服务] B2[订阅者列表] B3[粘性事件缓存] end subgraph ProcessB[&#34;进程B(订阅者)&#34;] C1[CommonEvent.subscribe] C2[回调函数] end subgraph ProcessC[&#34;进程C(订阅者)&#34;] D1[CommonEvent.subscribe] D2[回调函数] end A1 --> A2 A2 -->|Binder IPC| B1 B1 --> B2 B1 --> B3 B2 -->|匹配订阅者| C1 B2 -->|匹配订阅者| D1 C1 --> C2 D1 --> D2 classDef publisher fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px classDef manager fill:#fff3e0,stroke:#e65100,stroke-width:2px classDef subscriber fill:#e3f2fd,stroke:#1565c0,stroke-width:2px class A1,A2 publisher class B1,B2,B3 manager class C1,C2,D1,D2 subscriber

2.2 EventHandler架构

sequenceDiagram participant Worker as 工作线程 participant Handler as EventHandler participant Queue as 事件队列 participant Main as 主线程 Worker->>Handler: postEvent(eventId, param) Handler->>Queue: 入队事件 Queue->>Queue: 按时间排序 loop 事件循环 Main->>Queue: 取出事件 Queue-->>Main: 返回事件 Main->>Handler: processEvent() Handler->>Main: 执行回调 end

2.3 事件分发流程

typescript 复制代码
// CommonEvent分发流程(伪代码)
class CommonEventManager {
    private subscribers: Map<string, Subscriber[]> = new Map()
    private stickyEvents: Map<string, CommonEventData> = new Map()
  
    // 发布事件
    async publish(event: string, data: unknown, isSticky: boolean) {
        // 如果是粘性事件,缓存起来
        if (isSticky) {
            this.stickyEvents.set(event, data)
        }
      
        // 查找所有订阅者
        const subs = this.subscribers.get(event) || []
      
        // 通知所有订阅者
        for (const sub of subs) {
            await sub.callback(data)
        }
    }
  
    // 订阅事件
    subscribe(event: string, callback: Function, wantSticky: boolean) {
        // 添加到订阅者列表
        const subs = this.subscribers.get(event) || []
        subs.push({ callback })
        this.subscribers.set(event, subs)
      
        // 如果需要粘性事件,立即回调
        if (wantSticky && this.stickyEvents.has(event)) {
            callback(this.stickyEvents.get(event))
        }
    }
}

三、代码实战:CommonEvent使用

3.1 发布CommonEvent

typescript 复制代码
// CommonEventPublisher.ets
import { commonEventManager, CommonEventPublishData } from '@kit.BasicServicesKit'
import hilog from '@ohos.hilog'

const TAG = 'CommonEventPublisher'
const DOMAIN = 0xFF00

/**
 * CommonEvent发布者示例
 */
export class CommonEventPublisher {
  
    /**
     * 发布简单事件
     */
    static async publishSimpleEvent(): Promise<void> {
        try {
            // 发布简单事件(无参数)
            await commonEventManager.publish('com.example.MY_EVENT')
            hilog.info(DOMAIN, TAG, 'Simple event published')
        } catch (err) {
            hilog.error(DOMAIN, TAG, `Publish failed: ${err.message}`)
        }
    }
  
    /**
     * 发布带数据的事件
     */
    static async publishEventWithData(): Promise<void> {
        // 构建事件数据
        const options: CommonEventPublishData = {
            // 事件名称
            event: 'com.example.DATA_EVENT',
          
            // 事件数据(字符串)
            data: 'Hello from publisher',
          
            // 附加参数(键值对)
            parameters: {
                'userId': 1001,
                'userName': '张三',
                'timestamp': Date.now()
            }
        }
      
        try {
            await commonEventManager.publish(options)
            hilog.info(DOMAIN, TAG, 'Event with data published')
        } catch (err) {
            hilog.error(DOMAIN, TAG, `Publish failed: ${err.message}`)
        }
    }
  
    /**
     * 发布粘性事件
     * 粘性事件会被缓存,新订阅者订阅时立即收到
     */
    static async publishStickyEvent(): Promise<void> {
        const options: CommonEventPublishData = {
            event: 'com.example.STICKY_EVENT',
            data: 'This is a sticky event',
          
            // 标记为粘性事件
            isSticky: true,
          
            parameters: {
                'config': { theme: 'dark', lang: 'zh' }
            }
        }
      
        try {
            await commonEventManager.publish(options)
            hilog.info(DOMAIN, TAG, 'Sticky event published')
        } catch (err) {
            hilog.error(DOMAIN, TAG, `Publish failed: ${err.message}`)
        }
    }
  
    /**
     * 发布有序事件
     * 有序事件会按优先级依次分发给订阅者
     */
    static async publishOrderedEvent(): Promise<void> {
        const options: CommonEventPublishData = {
            event: 'com.example.ORDERED_EVENT',
            data: 'Ordered event data',
          
            // 标记为有序事件
            isOrdered: true
        }
      
        try {
            await commonEventManager.publish(options)
            hilog.info(DOMAIN, TAG, 'Ordered event published')
        } catch (err) {
            hilog.error(DOMAIN, TAG, `Publish failed: ${err.message}`)
        }
    }
  
    /**
     * 发布系统事件
     * 需要系统权限
     */
    static async publishSystemEvent(): Promise<void> {
        // 注意:系统事件需要系统签名或相应权限
        const options: CommonEventPublishData = {
            // 系统预定义事件
            event: 'android.intent.action.BATTERY_LOW',
            parameters: {
                'level': 15
            }
        }
      
        try {
            await commonEventManager.publish(options)
            hilog.info(DOMAIN, TAG, 'System event published')
        } catch (err) {
            hilog.error(DOMAIN, TAG, `Publish system event failed: ${err.message}`)
        }
    }
}

3.2 订阅CommonEvent

typescript 复制代码
// CommonEventSubscriber.ets
import { commonEventManager, CommonEventSubscribeInfo, CommonEventData } from '@kit.BasicServicesKit'
import hilog from '@ohos.hilog'

const TAG = 'CommonEventSubscriber'
const DOMAIN = 0xFF00

/**
 * CommonEvent订阅者示例
 */
export class CommonEventSubscriber {
    private subscriber: commonEventManager.CommonEventSubscriber = null
  
    /**
     * 订阅简单事件
     */
    async subscribeSimpleEvent(): Promise<void> {
        // 构建订阅信息
        const subscribeInfo: CommonEventSubscribeInfo = {
            events: ['com.example.MY_EVENT']
        }
      
        try {
            // 创建订阅者
            this.subscriber = await commonEventManager.createSubscriber(subscribeInfo)
          
            // 注册回调
            this.subscriber.subscribe((err, data: CommonEventData) => {
                if (err) {
                    hilog.error(DOMAIN, TAG, `Subscribe error: ${err.message}`)
                    return
                }
              
                hilog.info(DOMAIN, TAG, `Received event: ${data.event}`)
                hilog.info(DOMAIN, TAG, `Event data: ${data.data}`)
            })
          
            hilog.info(DOMAIN, TAG, 'Subscribed to simple event')
        } catch (err) {
            hilog.error(DOMAIN, TAG, `Subscribe failed: ${err.message}`)
        }
    }
  
    /**
     * 订阅多个事件
     */
    async subscribeMultipleEvents(): Promise<void> {
        const subscribeInfo: CommonEventSubscribeInfo = {
            // 订阅多个事件
            events: [
                'com.example.EVENT_A',
                'com.example.EVENT_B',
                'com.example.EVENT_C'
            ]
        }
      
        try {
            this.subscriber = await commonEventManager.createSubscriber(subscribeInfo)
          
            this.subscriber.subscribe((err, data: CommonEventData) => {
                if (err) {
                    hilog.error(DOMAIN, TAG, `Error: ${err.message}`)
                    return
                }
              
                // 根据事件类型处理
                switch (data.event) {
                    case 'com.example.EVENT_A':
                        this.handleEventA(data)
                        break
                    case 'com.example.EVENT_B':
                        this.handleEventB(data)
                        break
                    case 'com.example.EVENT_C':
                        this.handleEventC(data)
                        break
                }
            })
          
            hilog.info(DOMAIN, TAG, 'Subscribed to multiple events')
        } catch (err) {
            hilog.error(DOMAIN, TAG, `Subscribe failed: ${err.message}`)
        }
    }
  
    private handleEventA(data: CommonEventData) {
        hilog.info(DOMAIN, TAG, `Event A: ${data.data}`)
    }
  
    private handleEventB(data: CommonEventData) {
        hilog.info(DOMAIN, TAG, `Event B: ${data.data}`)
    }
  
    private handleEventC(data: CommonEventData) {
        hilog.info(DOMAIN, TAG, `Event C: ${data.data}`)
    }
  
    /**
     * 订阅粘性事件
     * 订阅时会立即收到之前发布的粘性事件
     */
    async subscribeStickyEvent(): Promise<void> {
        const subscribeInfo: CommonEventSubscribeInfo = {
            events: ['com.example.STICKY_EVENT'],
          
            // 请求接收粘性事件
            getStickEvent: true
        }
      
        try {
            this.subscriber = await commonEventManager.createSubscriber(subscribeInfo)
          
            this.subscriber.subscribe((err, data: CommonEventData) => {
                if (err) {
                    hilog.error(DOMAIN, TAG, `Error: ${err.message}`)
                    return
                }
              
                hilog.info(DOMAIN, TAG, `Received sticky event: ${data.data}`)
              
                // 读取附加参数
                const params = data.parameters
                if (params && params.config) {
                    hilog.info(DOMAIN, TAG, `Config: ${JSON.stringify(params.config)}`)
                }
            })
          
            hilog.info(DOMAIN, TAG, 'Subscribed to sticky event')
        } catch (err) {
            hilog.error(DOMAIN, TAG, `Subscribe failed: ${err.message}`)
        }
    }
  
    /**
     * 取消订阅
     */
    async unsubscribe(): Promise<void> {
        if (this.subscriber) {
            try {
                await this.subscriber.unsubscribe()
                hilog.info(DOMAIN, TAG, 'Unsubscribed')
                this.subscriber = null
            } catch (err) {
                hilog.error(DOMAIN, TAG, `Unsubscribe failed: ${err.message}`)
            }
        }
    }
}

3.3 EventHandler使用

typescript 复制代码
// EventHandlerDemo.ets
import { EventHandler, EventRunner } from '@kit.BasicServicesKit'
import hilog from '@ohos.hilog'

const TAG = 'EventHandlerDemo'
const DOMAIN = 0xFF00

/**
 * 自定义EventHandler
 */
export class MyEventHandler extends EventHandler {
  
    /**
     * 处理事件的核心方法
     * 在关联的线程中执行
     */
    processEvent(eventId: number, param: unknown): void {
        hilog.info(DOMAIN, TAG, `Processing event: ${eventId}`)
      
        switch (eventId) {
            case 1:
                this.handleUpdateUI(param)
                break
            case 2:
                this.handleDataLoaded(param)
                break
            case 3:
                this.handleNetworkResponse(param)
                break
            default:
                hilog.warn(DOMAIN, TAG, `Unknown event: ${eventId}`)
        }
    }
  
    private handleUpdateUI(param: unknown) {
        // 在主线程更新UI
        hilog.info(DOMAIN, TAG, `Update UI: ${JSON.stringify(param)}`)
    }
  
    private handleDataLoaded(param: unknown) {
        hilog.info(DOMAIN, TAG, `Data loaded: ${JSON.stringify(param)}`)
    }
  
    private handleNetworkResponse(param: unknown) {
        hilog.info(DOMAIN, TAG, `Network response: ${JSON.stringify(param)}`)
    }
}

/**
 * EventHandler使用示例
 */
export class EventHandlerExample {
    private mainHandler: MyEventHandler = null
    private workerHandler: MyEventHandler = null
    private workerRunner: EventRunner = null
  
    /**
     * 初始化主线程Handler
     */
    initMainHandler(): void {
        // 获取主线程的EventRunner
        const mainRunner = EventRunner.getMainEventRunner()
      
        // 创建主线程Handler
        this.mainHandler = new MyEventHandler(mainRunner)
      
        hilog.info(DOMAIN, TAG, 'Main handler initialized')
    }
  
    /**
     * 初始化工作线程Handler
     */
    async initWorkerHandler(): Promise<void> {
        // 创建工作线程的EventRunner
        this.workerRunner = EventRunner.create('WorkerThread')
      
        // 启动事件循环
        this.workerRunner.run()
      
        // 创建工作线程Handler
        this.workerHandler = new MyEventHandler(this.workerRunner)
      
        hilog.info(DOMAIN, TAG, 'Worker handler initialized')
    }
  
    /**
     * 发送即时事件
     */
    sendImmediateEvent(): void {
        // 发送到主线程
        this.mainHandler.sendEvent({
            eventId: 1,
            param: { message: 'Update UI now' }
        })
      
        hilog.info(DOMAIN, TAG, 'Immediate event sent')
    }
  
    /**
     * 发送延时事件
     */
    sendDelayedEvent(): void {
        // 延时5秒发送
        this.mainHandler.sendEvent({
            eventId: 2,
            param: { message: 'Delayed data' }
        }, 5000)  // 延时5000毫秒
      
        hilog.info(DOMAIN, TAG, 'Delayed event scheduled (5s)')
    }
  
    /**
     * 发送周期性事件
     */
    sendPeriodicEvent(): void {
        // 每3秒发送一次
        this.mainHandler.sendEvent({
            eventId: 3,
            param: { message: 'Periodic update' }
        }, 3000, true)  // 第三个参数表示周期性
      
        hilog.info(DOMAIN, TAG, 'Periodic event scheduled (every 3s)')
    }
  
    /**
     * 线程间通信示例
     * 工作线程完成任务后通知主线程
     */
    async crossThreadCommunication(): Promise<void> {
        // 在工作线程执行任务
        this.workerHandler.sendEvent({
            eventId: 100,
            param: { task: 'heavyWork' }
        })
      
        // 模拟工作线程处理后通知主线程
        setTimeout(() => {
            // 工作线程发送结果到主线程
            this.mainHandler.sendEvent({
                eventId: 1,
                param: {
                    result: 'Work completed',
                    data: [1, 2, 3, 4, 5]
                }
            })
        }, 2000)
      
        hilog.info(DOMAIN, TAG, 'Cross-thread communication started')
    }
  
    /**
     * 移除事件
     */
    removeEvent(eventId: number): void {
        this.mainHandler.removeEvent(eventId)
        hilog.info(DOMAIN, TAG, `Event ${eventId} removed`)
    }
  
    /**
     * 清理资源
     */
    cleanup(): void {
        if (this.workerRunner) {
            this.workerRunner.stop()
        }
        hilog.info(DOMAIN, TAG, 'Cleanup completed')
    }
}

3.4 实战:网络请求与UI更新

typescript 复制代码
// NetworkWithEventHandler.ets
import { EventHandler, EventRunner } from '@kit.BasicServicesKit'
import http from '@ohos.net.http'
import hilog from '@ohos.hilog'

const TAG = 'NetworkDemo'
const DOMAIN = 0xFF00

// 事件ID定义
const enum EventId {
    NETWORK_SUCCESS = 1,
    NETWORK_ERROR = 2,
    UPDATE_PROGRESS = 3
}

/**
 * 网络请求结果
 */
interface NetworkResult {
    url: string
    data: string
    statusCode: number
}

/**
 * 网络请求管理器
 * 使用EventHandler实现线程安全的网络请求
 */
export class NetworkManager {
    private mainHandler: EventHandler
    private httpRequest: http.HttpRequest
  
    constructor() {
        // 获取主线程Handler
        const mainRunner = EventRunner.getMainEventRunner()
        this.mainHandler = new EventHandler(mainRunner)
      
        // 创建HTTP请求对象
        this.httpRequest = http.createHttp()
    }
  
    /**
     * 发起网络请求
     * 在工作线程执行,完成后通知主线程
     */
    async fetchData(url: string): Promise<void> {
        hilog.info(DOMAIN, TAG, `Fetching: ${url}`)
      
        try {
            // 发起请求
            const response = await this.httpRequest.request(url, {
                method: http.RequestMethod.GET,
                connectTimeout: 60000,
                readTimeout: 60000
            })
          
            // 请求成功,通知主线程
            const result: NetworkResult = {
                url: url,
                data: response.result as string,
                statusCode: response.responseCode
            }
          
            this.mainHandler.sendEvent({
                eventId: EventId.NETWORK_SUCCESS,
                param: result
            })
          
        } catch (err) {
            // 请求失败,通知主线程
            this.mainHandler.sendEvent({
                eventId: EventId.NETWORK_ERROR,
                param: {
                    url: url,
                    error: err.message
                }
            })
        }
    }
  
    /**
     * 带进度的下载
     */
    async downloadWithProgress(url: string, destPath: string): Promise<void> {
        hilog.info(DOMAIN, TAG, `Downloading: ${url}`)
      
        // 模拟进度更新
        for (let progress = 0; progress <= 100; progress += 10) {
            // 通知主线程更新进度
            this.mainHandler.sendEvent({
                eventId: EventId.UPDATE_PROGRESS,
                param: {
                    url: url,
                    progress: progress
                }
            })
          
            // 模拟下载延迟
            await new Promise(resolve => setTimeout(resolve, 500))
        }
      
        // 下载完成
        this.mainHandler.sendEvent({
            eventId: EventId.NETWORK_SUCCESS,
            param: {
                url: url,
                data: destPath,
                statusCode: 200
            }
        })
    }
  
    /**
     * 销毁
     */
    destroy(): void {
        this.httpRequest.destroy()
    }
}

/**
 * UI组件使用示例
 */
@Entry
@Component
struct NetworkPage {
    @State data: string = 'Loading...'
    @State progress: number = 0
    @State errorMessage: string = ''
  
    private networkManager: NetworkManager = new NetworkManager()
    private eventHandler: EventHandler
  
    aboutToAppear() {
        // 创建EventHandler处理网络结果
        const mainRunner = EventRunner.getMainEventRunner()
        this.eventHandler = new EventHandler(mainRunner)
      
        // 处理事件
        this.eventHandler.setEventHandler((eventId, param) => {
            switch (eventId) {
                case EventId.NETWORK_SUCCESS:
                    this.handleSuccess(param as NetworkResult)
                    break
                case EventId.NETWORK_ERROR:
                    this.handleError(param)
                    break
                case EventId.UPDATE_PROGRESS:
                    this.handleProgress(param)
                    break
            }
        })
      
        // 发起请求
        this.networkManager.fetchData('https://api.example.com/data')
    }
  
    aboutToDisappear() {
        this.networkManager.destroy()
    }
  
    private handleSuccess(result: NetworkResult) {
        this.data = result.data
        hilog.info(DOMAIN, TAG, `Data loaded: ${result.data.length} chars`)
    }
  
    private handleError(error: { url: string, error: string }) {
        this.errorMessage = error.error
        hilog.error(DOMAIN, TAG, `Error: ${error.error}`)
    }
  
    private handleProgress(info: { url: string, progress: number }) {
        this.progress = info.progress
    }
  
    build() {
        Column() {
            Text('Network Data')
                .fontSize(24)
                .fontWeight(FontWeight.Bold)
          
            if (this.errorMessage) {
                Text(`Error: ${this.errorMessage}`)
                    .fontColor(Color.Red)
            } else if (this.progress > 0 && this.progress < 100) {
                Progress({ value: this.progress, total: 100, type: ProgressType.Linear })
                    .width('80%')
                Text(`${this.progress}%`)
            } else {
                Text(this.data)
                    .maxLines(10)
                    .textOverflow({ overflow: TextOverflow.Ellipsis })
            }
        }
        .width('100%')
        .height('100%')
        .justifyContent(FlexAlign.Center)
    }
}

四、踩坑与注意事项

4.1 坑一:CommonEvent订阅未取消

问题:订阅后忘记取消,导致内存泄漏和重复回调。

typescript 复制代码
// ❌ 错误示范:只订阅不取消
async subscribeEvent() {
    const subscriber = await commonEventManager.createSubscriber({
        events: ['com.example.EVENT']
    })
  
    subscriber.subscribe((err, data) => {
        // 处理事件
    })
  
    // 没有保存subscriber引用,无法取消!
}

// ✅ 正确做法:保存引用,适时取消
export class MyComponent {
    private subscriber: commonEventManager.CommonEventSubscriber = null
  
    async aboutToAppear() {
        this.subscriber = await commonEventManager.createSubscriber({
            events: ['com.example.EVENT']
        })
      
        this.subscriber.subscribe((err, data) => {
            // 处理事件
        })
    }
  
    async aboutToDisappear() {
        // 组件销毁时取消订阅
        if (this.subscriber) {
            await this.subscriber.unsubscribe()
        }
    }
}

4.2 坑二:EventHandler在错误线程

问题:在非主线程创建的EventHandler无法更新UI。

typescript 复制代码
// ❌ 错误示范:在工作线程创建Handler
import taskpool from '@ohos.taskpool'

@taskpool.task
function backgroundWork() {
    // 这里创建的Handler不在主线程!
    const handler = new EventHandler(EventRunner.create())
  
    handler.sendEvent({
        eventId: 1,
        param: { data: 'result' }
    })
    // 这个事件不会在主线程执行
}

// ✅ 正确做法:使用主线程Handler
export class CorrectExample {
    private mainHandler: EventHandler
  
    constructor() {
        // 在主线程创建Handler
        const mainRunner = EventRunner.getMainEventRunner()
        this.mainHandler = new EventHandler(mainRunner)
    }
  
    async doWork() {
        // 工作线程执行任务
        const result = await taskpool.execute(backgroundTask)
      
        // 通知主线程
        this.mainHandler.sendEvent({
            eventId: 1,
            param: result
        })
    }
}

4.3 坑三:CommonEvent权限问题

问题:某些系统事件需要特殊权限。

typescript 复制代码
// ❌ 订阅系统事件可能失败
await commonEventManager.createSubscriber({
    events: ['android.intent.action.BOOT_COMPLETED']  // 需要系统权限
})

// ✅ 检查权限并处理错误
async subscribeSystemEvent() {
    try {
        const subscriber = await commonEventManager.createSubscriber({
            events: ['android.intent.action.BOOT_COMPLETED']
        })
      
        subscriber.subscribe((err, data) => {
            if (err) {
                if (err.code === 201) {
                    // 权限不足
                    hilog.error(DOMAIN, TAG, 'Permission denied')
                } else {
                    hilog.error(DOMAIN, TAG, `Error: ${err.message}`)
                }
                return
            }
          
            // 处理事件
        })
    } catch (err) {
        hilog.error(DOMAIN, TAG, `Subscribe failed: ${err.message}`)
    }
}

4.4 坑四:事件循环阻塞

问题:EventHandler的事件处理函数执行时间过长,会阻塞后续事件。

typescript 复制代码
// ❌ 错误示范:事件处理函数执行太久
class SlowHandler extends EventHandler {
    processEvent(eventId: number, param: unknown) {
        // 耗时操作阻塞事件循环
        for (let i = 0; i < 1000000000; i++) {
            // 模拟耗时计算
        }
      
        // 后续事件都要等待
    }
}

// ✅ 正确做法:耗时操作异步处理
class FastHandler extends EventHandler {
    processEvent(eventId: number, param: unknown) {
        if (eventId === 1) {
            // 快速提取参数
            const data = param as HeavyData
          
            // 提交到工作线程处理
            taskpool.execute(() => {
                processHeavyData(data)
            })
          
            // 快速返回,不阻塞事件循环
        }
    }
}

4.5 坑五:粘性事件堆积

问题:粘性事件会一直缓存,可能导致数据过期。

typescript 复制代码
// ❌ 粘性事件一直存在
await commonEventManager.publish({
    event: 'com.example.CONFIG',
    data: JSON.stringify({ theme: 'light' }),
    isSticky: true
})

// 后续修改配置,但旧事件还在
await commonEventManager.publish({
    event: 'com.example.CONFIG',
    data: JSON.stringify({ theme: 'dark' }),
    isSticky: true
})
// 现在有两个粘性事件!

// ✅ 方案:发布前先清除旧的粘性事件
async publishConfig(config: object) {
    // 清除旧的粘性事件(如果API支持)
    // 或者在订阅时只处理最新的
    await commonEventManager.publish({
        event: 'com.example.CONFIG',
        data: JSON.stringify(config),
        isSticky: true
    })
}

五、HarmonyOS 6适配指南

5.1 API变更

变更项 HarmonyOS 5 HarmonyOS 6
CommonEvent导入 @ohos.commonEvent @kit.BasicServicesKit
订阅方式 回调嵌套 Promise + 回调分离
EventHandler创建 new EventHandler() new EventHandler(runner)
事件参数 多参数 单对象参数

5.2 新增功能

typescript 复制代码
// HarmonyOS 6新增:事件优先级
const subscribeInfo: CommonEventSubscribeInfo = {
    events: ['com.example.EVENT'],
  
    // 新增:设置订阅优先级(有序事件)
    priority: 100  // 数值越大优先级越高
}

// HarmonyOS 6新增:事件过滤
const subscribeInfo: CommonEventSubscribeInfo = {
    events: ['com.example.EVENT'],
  
    // 新增:设置发布者UID过滤
    publisherDeviceId: 'local',  // 只接收本地设备事件
  
    // 新增:设置发布者PID过滤
    publisherPid: 12345  // 只接收特定进程的事件
}

// HarmonyOS 6新增:异步订阅
async function asyncSubscribe() {
    const subscriber = await commonEventManager.createSubscriber(subscribeInfo)
  
    // 使用Promise风格的订阅
    subscriber.on('receive', (data: CommonEventData) => {
        console.log(`Received: ${data.event}`)
    })
  
    // 错误处理
    subscriber.on('error', (err: Error) => {
        console.error(`Error: ${err.message}`)
    })
}

5.3 性能优化

typescript 复制代码
// HarmonyOS 6:批量发送事件
class BatchEventHandler extends EventHandler {
    // 批量发送,减少上下文切换
    sendBatchEvents(events: Array<{ id: number, param: unknown }>) {
        for (const event of events) {
            this.sendEvent({
                eventId: event.id,
                param: event.param
            })
        }
    }
  
    // 使用延时合并相同事件
    private pendingEvents: Map<number, unknown> = new Map()
  
    sendDebounced(eventId: number, param: unknown, delay: number = 100) {
        // 保存最新参数
        this.pendingEvents.set(eventId, param)
      
        // 延时发送,多次调用会覆盖
        this.sendEvent({ eventId: -1, param: { type: 'debounce', targetId: eventId } }, delay)
    }
  
    processEvent(eventId: number, param: unknown) {
        if (eventId === -1) {
            // 处理延时合并
            const { type, targetId } = param as { type: string, targetId: number }
            if (type === 'debounce') {
                const actualParam = this.pendingEvents.get(targetId)
                this.pendingEvents.delete(targetId)
              
                // 发送实际事件
                this.processEvent(targetId, actualParam)
            }
            return
        }
      
        // 正常事件处理
        // ...
    }
}

六、总结一下下

6.1 核心要点回顾

graph TB A[事件驱动核心] --> B[CommonEvent] A --> C[EventHandler] B --> B1[跨进程通信] B --> B2[系统事件] B --> B3[粘性事件] C --> C1[线程间通信] C --> C2[延时任务] C --> C3[周期任务] classDef primary fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px classDef info fill:#e3f2fd,stroke:#1565c0,stroke-width:2px classDef warning fill:#fff3e0,stroke:#e65100,stroke-width:2px class A primary class B,C info class B1,B2,B3,C1,C2,C3 warning

6.2 最佳实践清单

  • CommonEvent订阅后记得取消
  • 使用主线程EventHandler更新UI
  • 处理权限不足的情况
  • 事件处理函数快速返回
  • 耗时操作异步处理
  • 粘性事件注意数据时效性
  • 使用try-catch处理错误
  • 合理设置事件优先级

6.3 选择指南

场景 推荐方案
跨进程通信 CommonEvent
系统事件监听 CommonEvent
线程间通信 EventHandler
UI更新通知 EventHandler(主线程)
延时任务 EventHandler
组件间通信 Emitter

相关推荐
Colin草率地做慢慢地改2 小时前
关于QuickStore这个项目的重构(2)- 数据库建表文件
后端·面试·架构
candyTong14 小时前
RTK 技术原理:一次典型会话里,80% 上下文是怎么省下来的
javascript·后端·架构
唐某人丶19 小时前
从画架构图开始:架构分析与进阶指南
架构
只会cv的前端攻城狮2 天前
DSL 领域模型架构设计:消灭 CRUD 重复工作
前端·架构
禅思院2 天前
路由性能优化终极指南:从懒加载漏洞到边缘渲染的架构跃迁
前端·架构·前端框架
怕浪猫2 天前
Electron 系列文章封面图
算法·架构·前端框架
王二端茶倒水2 天前
从千兆到万兆:小区、园区、酒店网络运营该怎么升级?
架构
喵个咪2 天前
技术复盘:基于 go-wind-cms 的官网+商城双业务渐进拆分实战
后端·架构·go