【HarmonyOS Next】重写一个通知中心

123 阅读3分钟
  • 本文所有代码案例均基于Api12。

在鸿蒙开发中,经常会遇到发送通知给其他类的需求。

大部分时候,我们会根据页面生命周期,在多个页面添加同一个消息事件监听,离开页面时只取消当前页面的监听,其他页面添加过监听的页面需要继续保持监听状态。

系统自带的通知里,如果一个消息事件添加了多处监听,在任意一处位置取消时,会同时取消该事件所有位置的监听。

所以,需要有一个通知管理类来承担这份工作。可以识别消息事件,还可以支持不同对象的注册和取消。

我自己写一个通知管理类解决这个问题。

调用方式如下:

// 页面构建时
aboutToAppear(): void {
  CustomNotification.register("test_event",this.getUniqueId(),()=>{
    // xxxxxx
  })
}

// 页面销毁时
aboutToDisappear(): void {
  CustomNotification.unRegister("test_event",this.getUniqueId())
}

// 发送消息时
CustomNotification.emit("test_event")
  • 参数说明: 1、注册方法中,第一个参数,是消息事件的key,同一个key的事件可以在多处注册;第二个参数是监听对象的id,用于区分同一个key下面的不同回调持有对象;第三个参数是回调方法,自己填写当前业务代码,这个参数是function,要自己注意对齐参数。 2、注销方法中,同样的需要填入消息事件的key和持有对象id。 3、这里的持有对象id使用了this.getUniqueId(),这个id是UI的唯一id,不用担心重复,省去了每次自己命名id的烦恼。

  • class里没有UniqueId,要给class对象添加通知怎么办? 我自己写的时候,class有时候也需要添加监听,所以我把这个id类型写成了联合类型 (type EventID = string | number) 根据业务场景,用字符串自定义一个key即可,比如:

CustomNotification.register("test_event",this.getUniqueId(),()=>{
      // xxxxxx
    })

以下是完整的通知类代码:

export namespace CustomNotification {
  /**
   * 事件id类型
   */
  type EventID = string | number

  /**
   * 监听事件
   */
  class Event {
    /**
     * 事件id
     */
    id: EventID
    /**
     * 事件回调
     */
    handle: Function

    constructor(id: EventID, handle: Function) {
      this.id = id
      this.handle = handle
    }
  }

  /**
   * 通知
   */
  class Notification {
    /**
     * 通知名
     */
    name: string
    /**
     * 事件队列
     */
    events: Event[] = []

    constructor(name: string) {
      this.name = name
    }
  }

  /**
   * 通知寄存处
   */
  let notifications: Notification[] = []

  /**
   * 注册通知
   * @param name 通知名
   * @param id 唯一(相对于这个通知名)的监听id,同一个对象内添加和移除时的id应该一致,重复的id不会影响监听,
   *           但可能会导致被其他地方相同id的监听移除
   * @param handle 回调方法
   */
  export function register(
    name: string,
    id: EventID,
    handle: Function
  ) {
    // 检查通知状态
    checkNotification(name)
    notifications.forEach((model: Notification) => {
      // 根据通知名找到通知
      if (model.name == name) {
        // 把监听事件插入通知
        model.events.push(new Event(id, handle))
      }
    })
  }

  /**
   * 检查通知状态,如果之前没有,就新增一个通知模型
   * @param name 通知名
   */
  function checkNotification(name: string) {
    let models = notifications.filter((model) => {
      return model.name == name
    })
    // 找不到就新增
    if (models.length == 0) {
      notifications.push(new Notification(name))
    }
  }

  /**
   * 调用通知消息
   * @param name 通知名
   * @param record 调用时的入参
   */
  export function emit(
    name: string,
    ...argArray: ESObject[]
  ) {
    notifications.forEach((notification: Notification) => {
      // 根据通知名找到通知
      if (notification.name == name) {
        // 调用通知的所有监听事件,并发送参数
        notification.events.forEach((event) => {
          // 调用时不区分id,这个通知所有的监听事件都会被触发
          event.handle(...argArray)
        })
      }
    })
  }

  /**
   * 取消监听事件
   * @param name 通知名
   * @param id 事件id
   */
  export function unRegister(
    name: string,
    id: EventID
  ) {
    notifications.forEach((notification: Notification) => {
      // 根据通知名找到通知
      if (notification.name == name) {
        // 根据id移除监听事件
        notification.events = notification.events.filter((event) => {
          return event.id != id
        })
      }
    })
    // 清理已经没有监听的空通知
    notifications = notifications.filter((model) => {
      return model.events.length > 0
    })
  }
}