【纯血鸿蒙】之liveeventbus消息总线

2,373 阅读3分钟

开始

最近在写鸿蒙项目发现页面与页面刷新数据不好使,提了工单说要我们要用AppStorage,当时懵了,到时候项目岂不是到处是AppStorage?官方是这么解释的AppStorage的

  • AppStorage:应用全局的UI状态存储
  • AppStorage是应用全局的UI状态存储,是和应用的进程绑定的,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储。
  • 和AppStorage不同的是,LocalStorage是页面级的,通常应用于页面内的数据共享。而AppStorage是应用级的全局状态共享,还相当于整个应用的“中枢”,持久化数据PersistentStorage环境变量Environment都是通过和AppStorage中转,才可以和UI交互。

但是官方也是不建议用AppStorage的,看看他怎么解释的

  • 不建议开发者使用@StorageLink和AppStorage的双向同步的机制来实现事件通知,AppStorage是和UI相关的数据存储,改变会带来UI的刷新,相对于一般的事件通知,UI刷新的成本较大。

下面来详解下liveeventbus的使用流程

效果图

企业微信截图_17165459241297.png

image.png

开发环境

  • Windows

  • DevEco Studio NEXT Developer Preview2

  • HarmonyOS next Developer Preview2

  • java version "11.0.18" 2023-01-17 LTS

  • hdc 1.2.0a

  • 手机:Mate 60Pro (HarmonyOS NEXT Developer Preview2)

导入liveeventbus库

"@ohos/liveeventbus": "^2.1.0"

封装工具类

  • 先new一下Lifecycle,注意:这里api9和api11写法不一样,因为api11加了很多约束
private mLifecycle: Lifecycle = new Lifecycle(MState.CREATED) //11写法

private mLifecycle: Lifecycle  //9写法
  • 接下来订阅/获取消息,这里我们用泛型,因为收到的消息可能是任意类型数据
/**
 * 订阅/获取消息
 * @param event
 */
getLiveEvent<T>(event: string, callBack: (isEvent: T) => void = () => {
}) {
  //创建生命周期感知对象
  this.mLifecycle = new Lifecycle(MState.STARTED)
  //订阅消息
  LiveEventBus
    .get<T>(event)
    .observe(this, {
      onChanged(b: T) {
        if (b) {
          callBack(b)
        }
      }
    });
}
  • 发送消息,同上也用泛型,因为发送可以是任意类型数据
/**
 * 发送消息
 * @param event
 * @param params
 */
sendLiveEvent<T>(event: string, params?: T | boolean) {
  if (params === undefined) {
    params = true; // 给 params 赋默认值
  }
  //发送消息
  LiveEventBus.get<T>(event).post(params as T);
}
  • 销毁消息
/**
 * 销毁消息
 */
destroyedLiveEvent() {
  this.mLifecycle.markState(MState.DESTROYED)
}
  • 生命周期感知对象
getLifecycle(): Lifecycle {
  return this.mLifecycle
}
  • 最后导出供业务层使用
let liveEventUtils = new LiveEventUtils()

export default liveEventUtils as LiveEventUtils;

使用

  • 因为消息会比较多,建议定义常量来进行区分
static readonly REFRESH_HOME_DATA = "refresh_home_data";
  • 为了测试发送event实体,建议单独定义一个包存event,我们定义一个event类
export interface TestEvent {
  event: string
}


export class TestEventModel implements TestEvent {
  event: string = ''

  constructor(model: TestEvent) {
    this.event = model.event
  }
}
  • 发送消息(默认消息和实体消息)
liveEventUtils.sendLiveEvent<boolean>(LiveEventConstant.REFRESH_HOME_DATA) //发送默认为true

liveEventUtils.sendLiveEvent<TestEvent>(LiveEventConstant.REFRESH_HOME_DATA, new TestEventModel({
  test: '测试'
})) //发送消息实体
  • 接收消息
//收到默认消息
liveEventUtils.getLiveEvent(LiveEventConstant.REFRESH_HOME_DATA, (isEvent: boolean) => {
  if (isEvent) {
    AlertDialog.show({ message: '收到消息了' + JSON.stringify(isEvent) })
  }
})

//收到实体消息
liveEventUtils.getLiveEvent(LiveEventConstant.REFRESH_HOME_DATA, (event: TestEvent) => {
  if (event) {
    AlertDialog.show({ message: '收到消息了' + JSON.stringify(event.title) })
  }
})

核心代码分析

其实原理很简单,就是利用创建生命周期感知对象,然后用observe来进行消息更新,跟安卓的LiveData、Lifecycle实现原理一样,底层是观察者模式

  • 看看这块代码是不是很熟悉?没错,就是MutableLiveData,其实安卓这块的liveData也是这样写的
class MutableLiveData<T> extends LiveData<T> {

    /**
     * Sets current LiveData value, and notifies observers.
     *
     * @param value The value to set.
     */
    public postValue(value: T) {
        this.data = value
        this.observers.forEach(observer => {
            observer.onChanged(value)
        })
    }

}

export default MutableLiveData
  • 然后用了一个LiveData用来观察更新
abstract class LiveData<T> {
    protected observers: Array<Observer<T>> = []

    protected data: T | null = null

    /**
     * Observes changes in LiveData value. If value set before observed, immediately invokes observer.
     *
     * @param observer  The observer to watch for changes.
     */
    public observe(observer: Observer<T>) {
        this.observers.push(observer)
        const tData = this.data
        if (tData != null) observer.onChanged(tData)
    }

    /**
     * @return  The current LiveData value.
     */
    public getValue(): T | null {
        return this.data
    }

    /**
     * Attempts to remove observer.
     *
     * @param observer  The observer to remove.
     *
     * @return  True if removed otherwise false.
     */
    public removeObserver(observer: Observer<T>): Boolean {
        const index = this.observers.indexOf(observer)
        if (index != -1) {
            this.observers.splice(index, 1)
            return true
        }
        return false
    }

    /**
     * Removes all observers.
     */
    public removeAllObservers() {
        this.observers.splice(0, this.observers.length)
    }

    /**
     * @return  A read-only version of observers.
     *          Mostly used for testing.
     */
    getObservers(): ReadonlyArray<Observer<T>> {
        return this.observers
    }
}
  • 接下来Observer接口有个onChanged方法,这个方法其实才是核心
interface Observer<T> {
  /**
     * Called when the data is changed.
     * @param t  The new data
     */
  onChanged(t:T):void;
}
  • 好了,就到这了,祝大家周末愉快!

    下集预告

    下一篇我们来写一个首页渐变

    本文正在参加华为鸿蒙有奖征文征文活动