1. 利用 applicationStateChange 监听前后台变化
参考文档:
private _stateCallback?: ApplicationStateCallback
// 利用对象字面量初始化 ApplicationStateChangeCallback class
// 这是官方示例的写法,API 的设计方式比较奇怪
private _applicationStateChangeCallback: ApplicationStateChangeCallback = {
// 换用箭头函数改变 this 指向
onApplicationForeground: () => {
if (this._stateCallback) {
this._stateCallback('Foreground')
}
},
onApplicationBackground: () => {
if (this._stateCallback) {
this._stateCallback('Background')
}
}
}
// 启动App前后台监听
startWatchingApplicationStateChange(callback: ApplicationStateCallback) {
this._stateCallback = callback
// 间接应用的应用上下文
let applicationContext = Util.getContext().getApplicationContext()
try {
if (applicationContext != undefined) {
applicationContext.on('applicationStateChange', this._applicationStateChangeCallback)
}
} catch (err) {
}
}
// 停止App前后台监听
stopWatchingApplicationStateChange() {
let applicationContext = Util.getContext().getApplicationContext()
try {
if (applicationContext != undefined) {
applicationContext.off('applicationStateChange', this._applicationStateChangeCallback)
this._stateCallback = undefined
}
} catch (er) {
}
}
2. 利用 windowStageEvent、windowEvent 监听窗口生命周期变化
参考文档:
| 名称 | 值 | 说明 |
|---|---|---|
| WINDOW_SHOWN | 1 | 切到前台。系统能力: SystemCapability.WindowManager.WindowManager.Core。 |
| WINDOW_ACTIVE | 2 | 获焦状态。系统能力: SystemCapability.WindowManager.WindowManager.Core。 |
| WINDOW_INACTIVE | 3 | 失焦状态。系统能力: SystemCapability.WindowManager.WindowManager.Core。 |
| WINDOW_HIDDEN | 4 | 切到后台。系统能力: SystemCapability.WindowManager.WindowManager.Core。 |
| WINDOW_DESTROYED11+ | 7 | 窗口销毁。系统能力: SystemCapability.Window.SessionManager。 |
建议使用 windowStageEventType ,避免 App 多窗口的情况导致监听错误:
| 名称 | 值 | 说明 |
|---|---|---|
| SHOWN | 1 | 切到前台,例如点击应用图标启动,无论是首次启动还是从后台启动均会触发。 |
| ACTIVE | 2 | 获焦状态,例如应用窗口处理点击事件后的状态、应用启动后的状态。 |
| INACTIVE | 3 | 失焦状态,例如打开新应用或点击其他窗口后,原获焦窗口的状态。 |
| HIDDEN | 4 | 切到后台,例如应用上滑退出、应用窗口关闭。 |
| RESUMED11+ | 5 | 前台可交互状态,例如应用打开后,可以与用户交互的状态。 |
| PAUSED11+ | 6 | 前台不可交互状态,例如从屏幕底部上划,应用进入到多任务界面后的状态。 |
这里可以根据窗口管理器或主窗口的生命周期变化,间接监听 App 的前后台事件:
// 获取 App 主窗口
const windowStage = Util.getWindowStage()
// 窗口管理器
windowStage.on('windowStageEvent', (windowStageEventType: window.WindowStageEventType) => {
console.info('windowStageEventType: windowStageEventType);
})
// 主窗口
windowStage.getMainWindowSync().on('windowEvent', (windowEventType: window.WindowEventType) => {
console.log('windowEventType: ', windowEventType)
})
App 切换前后台时,窗口生命周期变化的日志对应关系:
// App 切后台
windowStageEventType/windowEventType: 3
windowStageEventType/windowEventType: 4
// App 切前台
windowStageEventType/windowEventType: 1
windowStageEventType/windowEventType: 2
3. 利用 abilityLifecycle 监听应用生命周期
注册 abilityLifecycle 监听应用内生命周期,可以使用callback做异步回调,该 API 仅支持主线程调用。
- ApplicationContext.on('abilityLifecycle')
- @ohos.app.ability.abilityLifecycleCallback (AbilityLifecycleCallback)
App切换前后台时,相对完整的生命周期示意日志:
// App 切后台
AbilityLifecycleCallback onWindowStageInactive
AbilityLifecycleCallback onAbilityWillBackground
AbilityLifecycleCallback onAbilityBackground
// App 切前台
AbilityLifecycleCallback onWillNewWant
AbilityLifecycleCallback onNewWant
AbilityLifecycleCallback onAbilityWillForeground
AbilityLifecycleCallback onAbilityForeground
AbilityLifecycleCallback onWindowStageActive
这里对应窗口生命周期的失焦获焦有:
- 注册监听应用上下文的生命周期后,在windowStage失焦时触发回调: onWindowStageInactive(ability: UIAbility, windowStage: window.WindowStage): void
- 注册监听应用上下文的生命周期后,在windowStage获焦时触发回调: onWindowStageActive(ability: UIAbility, windowStage: window.WindowStage): void
- 这两个个生命周期和 iOS 有点类似,可以替代前后台监听:
但是要特别注意:系统级弹窗(例如权限授权弹窗),或者自定义 subwindow 的浮窗,都会触发 onWindowStageInactive 周期,因为此时主窗口失焦,除非自定义 subwindow 的浮窗是不可交互的蒙层。所以监听前后台具体选用的周期,要特别谨慎
- 示例代码(参考官方示例):
export enum AppState {
AppWindowStageActive,
AppWindowStageInactive
}
type AppStateCallback = (state: AppState, ability?: UIAbility, windowStage?: window.WindowStage) => void
// 应用内生命周期监听回调
public startWatchingAbilityLifecycle(callback: AppStateCallback) {
// 注意 AbilityLifecycleCallback 是 class,其中某些方法是必选实现,无法用 Partial 过滤
// 官方示例也是用对象字面量初始化的这个类(不规范)
// 可以考虑用继承的方式过滤不必要的实现
let callback: AbilityLifecycleCallback = {
onAbilityCreate(ability: UIAbility) {
},
onWindowStageCreate(ability, windowStage) {
},
// 在windowStage获焦时触发回调
onWindowStageActive: (ability, windowStage) => {
callback?.(AppState.WindowStageActive, ability, windowStage)
},
// 在windowStage失焦时触发回调
onWindowStageInactive: (ability, windowStage) => {
callback?.(AppState.WindowStageInactive, ability, windowStage)
},
onWindowStageDestroy(ability, windowStage) {
},
onAbilityDestroy(ability) {
},
onAbilityForeground: (ability) => {
},
onAbilityBackground: (ability) => {
},
onAbilityContinue(ability) {
}
}
let applicationContext = Util.getContext().getApplicationContext();
try {
this.lifecycleId = applicationContext.on('abilityLifecycle', callback);
} catch (err) {
}
}
// 停止App生命周期监听
stopWatchingAbilityLifecycle() {
let applicationContext = Util.getContext().getApplicationContext();
try {
applicationContext.off('abilityLifecycle', this.lifecycleId, (error, data) => {
});
} catch (err) {
}
}
- 优化后,相对符合编码规范的实现:
// 通过继承过滤方法回调
class PartialAbilityLifecycleCallback extends AbilityLifecycleCallback {
constructor(callback: AppStateCallback) {
super()
this.callback = callback
}
callback?: AppStateCallback
// 在windowStage获焦时触发回调
onWindowStageActive(ability: UIAbility, windowStage: window.WindowStage) {
super.onWindowStageActive(ability, windowStage)
this.callback?.(AppState.WindowStageActive, ability, windowStage)
}
// 在windowStage失焦时触发回调
onWindowStageInactive(ability: UIAbility, windowStage: window.WindowStage) {
super.onWindowStageInactive(ability, windowStage)
this.callback?.(AppState.WindowStageInactive, ability, windowStage)
}
}
// 实现
let applicationContext = Util.getContext().getApplicationContext();
try {
this.lifecycleId = applicationContext.on('abilityLifecycle', new PartialAbilityLifecycleCallback(callback));
} catch (err) {
}