当前位置: 首页 > news >正文

HarmonyOS - UIObserver(无感监听)

@[TOC](HarmonyOS - UIObserver(无感监听))

概述

本篇文档主要介绍,在鸿蒙项目开发过程中,我们如何使用UIObserver对象提供的对UI组件行为变化的无感监听能力。

基于当前鸿蒙项目, 我们是把页面所有的数据都存放在一个叫UIState对象中, 并且ViewModel持有这个UIState对象,而且ViewModel中包含了所有业务的逻辑。

当我们在ViewModel中请求数据时,需要知道在什么时机去请求, 那么我们就需要再ViewModel中知道View的一些生命周期方法的变化。

使用鸿蒙提供的UIObserver即可实现该效果。

UIObserver无感监听Router

监听代码:

// 获取UIObserver对象
const lifecycleObserver: UIObserver = uiContext.getUIObserver()
lifecycleObserver.on('routerPageUpdate', (routerPageInfo: RouterPageInfo) => {console.log(`[lifecycle] routerPageUpdate============: ${this.stringify(routerPageInfo)}`)})

通过Router的方式push一个PageThree页面, 输出结果如下:
在这里插入图片描述
我们可以看到在页面状态发生变化时,注册的回调将会触发,开发者可以通过回调中传入的入参拿到页面的相关信息,如:页面的名字,索引,路径,生命周期状态等

回调方法的RouterPageInfo对象包含了上述的所有信息

UIObserver无感监听Navigation

示例代码:

const lifecycleObserver: UIObserver = uiContext.getUIObserver()// 监听navDestination组件 切换到另外一个navDestination组件的变化
lifecycleObserver.on('navDestinationSwitch', (navDestinationSwitchInfo: uiObserver.NavDestinationSwitchInfo) => {console.log(`[lifecycle] navDestinationSwitch==================: ${this.stringify(navDestinationSwitchInfo)}`)})// 监听navDestination组件(页面)生命周期发生变化lifecycleObserver.on('navDestinationUpdate', (navDestinationInfo: NavDestinationInfo) => {console.log(`[lifecycle] navDestinationUpdate=====================: ${this.stringify(navDestinationInfo)}`)})

输出结果:
在这里插入图片描述

根据结果可以知道, 通过上面的两个方法的监听, 我们可以知道页面的来源,当前页面的生命周期变化等信息。

UIObserver无感监听Tab

// 获取UIObserver对象
const lifecycleObserver: UIObserver = uiContext.getUIObserver()
// 注册tabContentUpdate的监听, 当tabContent组件变化时会回调
lifecycleObserver.on('tabContentUpdate', (tabContentInfo: uiObserver.TabContentInfo) => {console.log(`[lifecycle] tabContentUpdate====================: ${this.stringify(tabContentInfo)}`)})

测试结果:
在这里插入图片描述

其实关于UIObserver, 这里只介绍了比较常用的三种,官网文档中其实还有很多无感监听其他事件的api, 如果想知道更多请参考官方文档UIObsever官方文档

UIObserver的工具类封装

工具类示例代码

import { ArrayList } from '@kit.ArkTS'
import { router, uiObserver, UIObserver } from '@kit.ArkUI'export interface ILifecycleId {tabId?: stringpageId?: stringnavDestinationId?: string
}export function getLifecycleId(component: CustomComponent, tabId?: string): ILifecycleId {return {tabId: tabId,pageId: component.queryRouterPageInfo()?.pageId,navDestinationId: component.queryNavDestinationInfo()?.navDestinationId,}
}/*** 定义页面的个个生命周期的枚举, 具体的值参考个个监听回调方法中的状态值*/
export enum LifecycleState {onCreate = 'onCreate', // 页面创建的时候onVisible = 'onVisible', // 页面显示onInvisible = 'onInvisible', // 页面隐藏onDestroy = 'onDestroy', // 页面onTabSelect = 'onTabSelect', // TabContent 组件显示(选中)onTabUnselect = 'onTabUnselect', // TabContent组件隐藏(未选中)
}// 定义一个生命周期状态变量
export type TabLifeState = LifecycleState.onVisible | LifecycleState.onInvisible | LifecycleState.onTabSelect| LifecycleState.onTabUnselect/*** 定义一个页面信息对象*/
export interface ILifecycleObserver {tabId?: stringpageId?: stringnavDestinationId?: stringuiAbility?: booleanonReceive: (state: LifecycleState) => void
}export class Lifecycle {/** 缓存监听的对象列表 */private observerList: ArrayList<ILifecycleObserver> = new ArrayList()/** 缓存Router下监听的列表 */private routerPageInfoMap: Map<string, uiObserver.RouterPageInfo> = new Map()/** 缓存navDestination监听的列表 */private navDestinationStateMap: Map<string, uiObserver.NavDestinationState> = new Map()// private mainTabSelectProvider?: IMainTabSelectProvider// private uiAbilityLifecycleProvider?: IUIAbilityLifecycleProviderinit(uiContext: UIContext) {const lifecycleObserver: UIObserver = uiContext.getUIObserver()// 无感监听router页面变化回调方法lifecycleObserver.on('routerPageUpdate', (routerPageInfo: RouterPageInfo) => {console.log(`[lifecycle] routerPageUpdate============: ${this.stringify(routerPageInfo)}`)// 把Router栈中的页面都缓存到map中this.routerPageInfoMap.set(routerPageInfo.pageId, routerPageInfo)// 处理Router个个page的生命周期回调this.handlePageState(routerPageInfo.pageId, routerPageInfo.state)// 移除已经销毁页面的监听this.checkRemoveIfOnPageDestroy(routerPageInfo)})lifecycleObserver.on('tabContentUpdate', (tabContentInfo: uiObserver.TabContentInfo) => {console.log(`[lifecycle] tabContentUpdate====================: ${this.stringify(tabContentInfo)}`)// 该方法可以处理})// 监听Navigation的页面切换事件。lifecycleObserver.on('navDestinationSwitch', (navDestinationSwitchInfo: uiObserver.NavDestinationSwitchInfo) => {console.log(`[lifecycle] navDestinationSwitch==================: ${this.stringify(navDestinationSwitchInfo)}`)// 如果我们整个项目是直接使用Navigation, 我们可以在这个监听方法内部, 判断是否回到主页面let mainPageState: LifecycleState | undefined// 判断是否从主界面跳转来的if(navDestinationSwitchInfo.from === 'navBar') {mainPageState = LifecycleState.onInvisible} else if(navDestinationSwitchInfo.to === 'navBar') {// 判断是否从其他页面回到主页面mainPageState = LifecycleState.onVisible}if(!mainPageState) {return}// 如果你是采用Router + Navigation 实现页面跳转, 可如下判断是否回到主页 (例如: 登录,欢迎页使用router, 主页使用Navigation)const mainRoutePageInfoFound = Array.from(this.routerPageInfoMap.values()).find((routePageInfo) => routePageInfo.name === 'main' )if(!mainRoutePageInfoFound) {return}// 处理回到主页事件this.dispatchMainPageEvent(mainRoutePageInfoFound.pageId, mainPageState)})// 监听NavDestination组件的状态变化。  生命周期方法的变化lifecycleObserver.on('navDestinationUpdate', (navDestinationInfo: NavDestinationInfo) => {console.log(`[lifecycle] navDestinationUpdate=====================: ${this.stringify(navDestinationInfo)}`)// 缓存每个NavDestination路由的状态this.navDestinationStateMap.set(navDestinationInfo.navDestinationId, navDestinationInfo.state)// 处理NavDestination的状态this.handleNavDestinationState(navDestinationInfo.navDestinationId, navDestinationInfo.state)// 处理销毁的NavDestinationthis.checkRemoveIfOnNavDestinationDestroy(navDestinationInfo)})}private stringify(value: object) {const body = JSON.stringify(value, (_, v: object) => {const value: string | object = typeof v === 'bigint' ? (v as bigint).toString() : vreturn value})return body}private checkRemoveIfOnNavDestinationDestroy(navDestinationInfo: uiObserver.NavDestinationInfo) {if (navDestinationInfo.state === uiObserver.NavDestinationState.ON_DISAPPEAR) {const observerMatch = this.observerList.convertToArray().find((observer) => observer.navDestinationId === navDestinationInfo.navDestinationId)if (observerMatch) {this.removeObserver(observerMatch)}}}/*** 当前页面销毁时,我们需要删除该页面的监听* @param routerPageInfo*/private checkRemoveIfOnPageDestroy(routerPageInfo: uiObserver.RouterPageInfo) {if (routerPageInfo.state === uiObserver.RouterPageState.ABOUT_TO_DISAPPEAR) {const observerMatch =this.observerList.convertToArray().find((observer) => observer.pageId === routerPageInfo.pageId)if (observerMatch) {this.removeObserver(observerMatch)}}}/*** 处理Router 中page的State方法* @param pageId 页面id* @param pageState 页面当前的生命周期状态*/private handlePageState(pageId: string, pageState: uiObserver.RouterPageState) {switch (pageState) {case uiObserver.RouterPageState.ABOUT_TO_APPEAR:this.dispatchPageEvent(pageId, LifecycleState.onCreate)breakcase uiObserver.RouterPageState.ON_PAGE_SHOW:this.dispatchPageEvent(pageId, LifecycleState.onVisible)breakcase uiObserver.RouterPageState.ON_PAGE_HIDE:this.dispatchPageEvent(pageId, LifecycleState.onInvisible)breakcase uiObserver.RouterPageState.ABOUT_TO_DISAPPEAR:this.dispatchPageEvent(pageId, LifecycleState.onDestroy)break}}private handleNavDestinationState(navDestinationId: string, pageState: uiObserver.NavDestinationState) {switch (pageState) {case uiObserver.NavDestinationState.ON_APPEAR:this.dispatchNavDestinationEvent(navDestinationId, LifecycleState.onCreate)breakcase uiObserver.NavDestinationState.ON_SHOWN:this.dispatchNavDestinationEvent(navDestinationId, LifecycleState.onVisible)breakcase uiObserver.NavDestinationState.ON_HIDDEN:this.dispatchNavDestinationEvent(navDestinationId, LifecycleState.onInvisible)breakcase uiObserver.NavDestinationState.ON_DISAPPEAR:this.dispatchNavDestinationEvent(navDestinationId, LifecycleState.onDestroy)break}}private dispatchMainPageEvent(pageId: string, state: LifecycleState) {this.observerList.convertToArray().filter((observer) => observer.pageId === pageId).forEach((observer: ILifecycleObserver) => {this.doDispatchPageEvent(observer, state)})}/*** 处理NavDestination发生变化时的回调* @param navDestinationId  NavDestination组件的id* @param state 生命周期状态*/private dispatchNavDestinationEvent(navDestinationId: string, state: LifecycleState) {this.observerList.convertToArray().filter((observer) => observer.navDestinationId === navDestinationId).forEach((observer: ILifecycleObserver) => {observer.onReceive(state)})}/*** 处理Router中页面的变化时的回调* @param pageId router page的id* @param state 生命周期状态*/private dispatchPageEvent(pageId: string, state: LifecycleState) {this.observerList.convertToArray().filter((observer) => observer.pageId === pageId).forEach((observer: ILifecycleObserver) => {observer.onReceive(state)})}private doDispatchPageEvent(observer: ILifecycleObserver, state: LifecycleState) {if (observer.navDestinationId) {return}if (!observer.tabId) {observer.onReceive(state)return}observer.onReceive(state)}private dispatchUIAbilityEvent(state: LifecycleState) {this.observerList.convertToArray().filter((observer) => observer.uiAbility === true).forEach((observer: ILifecycleObserver) => {// logger.debug(`[lifecycle][uiAbility] onReceive ${state}`)observer.onReceive(state)})}selectTab(tabId: string) {this.dispatchTabEvent(tabId, LifecycleState.onTabSelect)this.dispatchTabEvent(tabId, LifecycleState.onVisible)}unselectTab(tabId: string) {this.dispatchTabEvent(tabId, LifecycleState.onTabUnselect)this.dispatchTabEvent(tabId, LifecycleState.onInvisible)}private dispatchTabEvent(tabId: string, state: TabLifeState) {this.observerList.convertToArray().filter((observer) => observer.tabId === tabId).forEach((observer: ILifecycleObserver) => {this.doDispatchTabEvent(observer, state)})}private doDispatchTabEvent(observer: ILifecycleObserver, state: TabLifeState) {if (!observer.pageId) {observer.onReceive(state)return}const pageInfo = this.routerPageInfoMap.get(observer.pageId)if (pageInfo?.state === uiObserver.RouterPageState.ON_PAGE_SHOW) {observer.onReceive(state)}}// 增加一个页面监听addObserver(observer: ILifecycleObserver, sticky: boolean = true) {this.observerList.add(observer)if (sticky) {this.observerUICallbackSticky(observer)}}private observerUICallbackSticky(observer: ILifecycleObserver) {const lifecycleState = this.fetchLifecycleState(observer)if (!lifecycleState) {return}if (lifecycleState === LifecycleState.onDestroy) {observer.onReceive(LifecycleState.onInvisible)observer.onReceive(LifecycleState.onDestroy)return}if (!observer.tabId) {observer.onReceive(LifecycleState.onCreate)if (lifecycleState !== LifecycleState.onCreate) {if (observer.navDestinationId) {this.dispatchNavDestinationEvent(observer.navDestinationId, lifecycleState)} else if (observer.pageId) {this.doDispatchPageEvent(observer, lifecycleState)}}return}}private fetchLifecycleState(observer: ILifecycleObserver): LifecycleState | undefined {let lifecycleState: LifecycleState | undefinedconst pageId = observer.pageIdconst navDestinationId = observer.navDestinationIdif (pageId) {const pageInfo = this.routerPageInfoMap.get(pageId)lifecycleState = pageInfo ? transformLifecycleStateFromPage(pageInfo.state) : undefined} else if (navDestinationId) {const destinationState = this.navDestinationStateMap.get(navDestinationId)lifecycleState = destinationState ? transformLifecycleStateFromNavDestination(destinationState) : undefined}return lifecycleState}/*** 移除一个页面监听* @param observer*/removeObserver(observer: ILifecycleObserver) {this.observerList.remove(observer)}release() {this.observerList.clear()}
}function transformLifecycleStateFromPage(pageState: uiObserver.RouterPageState): LifecycleState | undefined {switch (pageState) {case uiObserver.RouterPageState.ABOUT_TO_APPEAR:return LifecycleState.onCreatecase uiObserver.RouterPageState.ABOUT_TO_DISAPPEAR:return LifecycleState.onDestroycase uiObserver.RouterPageState.ON_PAGE_SHOW:return LifecycleState.onVisiblecase uiObserver.RouterPageState.ON_PAGE_HIDE:return LifecycleState.onInvisibledefault:return undefined}}function transformLifecycleStateFromNavDestination(navDestinationState: uiObserver.NavDestinationState): LifecycleState | undefined {switch (navDestinationState) {case uiObserver.NavDestinationState.ON_APPEAR:return LifecycleState.onCreatecase uiObserver.NavDestinationState.ON_DISAPPEAR:return LifecycleState.onDestroycase uiObserver.NavDestinationState.ON_SHOWN:return LifecycleState.onVisiblecase uiObserver.NavDestinationState.ON_HIDDEN:return LifecycleState.onInvisibledefault:return undefined}}export const lifecycle = new Lifecycle()

工具类使用示例

  1. 首先我们需要在EntryAbility类中,初始化这个工具类
onWindowStageCreate(windowStage: window.WindowStage): void {// 初始化工具类windowStage.getMainWindow().then((window) => {// 初始化生命周期的对象方法lifecycle.init(window.getUIContext())})}
  1. 在页面中的应用
//TestPage.ets
import { ILifecycleId } from "./Lifecycle"
import { TestView } from "./TestView"@Component
export struct TestPage {build() {NavDestination() {TestView({onReady: (lifecycleId: ILifecycleId) => {// 调用逻辑层的生命周期执行方法, 比如viewmodel中的监听方法}})}}
}// TestView.ets
import { getLifecycleId, ILifecycleId } from './Lifecycle'@Component
export struct TestView {onReady: (lifecycleId: ILifecycleId) => void = () => {}aboutToAppear(): void {this.onReady(getLifecycleId(this))}build() {Column() {}}
}

注意:getLifecycleId(this)这个句代码是能直接放在TestPage的aboutToAppear生命周期方法中的, 因为此时的NavDestination并没有创建,所以获取的navDestinationId都是undefined

相关文章:

  • Windows 安装以及配置Docker全流程 - Docker Toolbox
  • vibe coding 2025工具全景图
  • python打卡day51@浙大疏锦行
  • 如何利用测试Agent自动分析覆盖率报告与缺陷趋势
  • “十五五”时期智慧城市赋能全国一体化数据市场建设:战略路径与政策建议[ 注:本建议基于公开政策文件与行业实践研究,数据引用截至2025年6月11日。]
  • 剑指offer21——反转链表
  • 力扣上C语言编程题:最大子数组和(涉及数组)
  • Qwen3-Embedding-8B:文本嵌入界的“卷王”,多语言检索新标杆!
  • 嵌入式学习笔记 - C语言访问地址的方式,以及指针的进一步理解
  • 简单的五子棋实现简介
  • 6.11本日总结
  • typescript中的泛型
  • 字符串|数组|计算常见函数整理-竞赛专用(从比赛真题中总结的,持续更新中)
  • 使用CSDN作为Markdown编辑器图床
  • 【Python-Day 25】玩转数字:精通 math 与 random 模块,从数学运算到随机抽样
  • 图文教程——Deepseek最强平替工具免费申请教程——国内edu邮箱可用
  • 亚马逊Woot黑五策略,快速提升亚马逊业绩
  • LeetCode - 136. 只出现一次的数字
  • vue3 + ant 实现 tree默认展开,筛选对应数据打开,简单~直接cv
  • Java异步编程难题
  • 廉洁 网站建设/网站制作工具有哪些
  • 盗版网站是如何做的/百度公司招聘
  • 做影视网站存储视频会侵权吗/新网站seo
  • 深圳网站建设hi0755/模板建站哪个平台好
  • 购物网站开发需求文档/手机360优化大师官网
  • 网站的布局方式有哪些方面/怎样自己做网站