Openharmony应用开发之Ability异常退出与UIAbility数据备份开发实战

概述

AbilityStage在首次加载时会创建一个AbilityStage实例,可以对该Module进行初始化等操作。AbilityStage与Module一一对应,即一个Module拥有一个AbilityStage。

AbilityStage拥有onCreate()、onDestroy()生命周期回调和onAcceptWant()、onConfigurationUpdate()、onMemoryLevel()、onNewProcessRequest()、onPrepareTermination()等事件回调。

  • onCreate()生命周期回调:在开始加载对应Module的第一个应用组件(如UIAbility组件或具体扩展能力的ExtensionAbility组件实例之前会先创建AbilityStage,并在AbilityStage创建完成之后执行其onCreate()生命周期回调。AbilityStage模块提供在Module加载的时候,通知开发者,可以在此进行该Module的初始化(如资源预加载、线程创建等)。

  • onAcceptWant()事件回调:UIAbility指定实例模式specified启动模式)启动时候触发的事件回调。

  • onConfigurationUpdate()事件回调:当系统全局配置(例如系统语言、深浅色等)发生变更时触发的事件回调,配置项均定义在Configuration类中。

  • onMemoryLevel()事件回调:当系统调整内存时触发的事件回调。应用被切换到后台时,系统会将在后台的应用保留在缓存中。即使应用处于缓存中,也会影响系统整体性能。当系统资源不足时,系统会通过多种方式从应用中回收内存,必要时会完全停止应用,从而释放内存用于执行关键任务。为了进一步保持系统内存的平衡,避免系统停止用户的应用进程,可以在AbilityStage中的onMemoryLevel()生命周期回调中订阅系统内存的变化情况,释放不必要的资源。

  • onNewProcessRequest()事件回调:UIAbility启动时触发的事件回调。通过该回调,开发者可以指定每个UIAbility启动时是否在独立的进程中创建。该回调返回一个开发者自定义字符串标识,如果返回的字符串标识为开发者曾创建的,则复用该标识所对应的进程,否则创建新的进程。需要注意该回调需要配合在module.json5中声明isolationProcess字段为true。当前仅在2in1设备上生效。

  • onPrepareTermination()事件回调:当应用被用户关闭时调用,可用于询问用户选择立即执行操作还是取消操作。开发者通过在回调中返回AbilityConstant.PrepareTermination中定义的枚举类型通知系统是否继续执行关闭动作。当前仅在2in1设备上生效。

  • onDestroy()生命周期回调:当对应Module的最后一个Ability实例退出后触发。此方法仅在应用正常销毁时触发。当应用程序异常退出或被终止时,将不会调用此方法。

例如onCreate回调

ts 复制代码
import { AbilityStage, Want } from '@kit.AbilityKit';

export default class MyAbilityStage extends AbilityStage {
  onCreate(): void {
    // 应用HAP首次加载时触发,可以在此执行该Module的初始化操作(例如资源预加载、线程创建等)。
  }

  onAcceptWant(want: Want): string {
    // 仅specified模式下触发
    return 'MyAbilityStage';
  }
}

1. Ability的设计使用场景

  • 应用的多Module开发:应用可通过不同类型的Module(HAP、HAR、HSP)来实现应用的功能开发。其中,HAP用于实现应用的功能和特性,HAR与HSP用于实现代码和资源的共享。
  • 应用内的交互:应用内的不同组件之间可以相互跳转。比如,在支付应用中,通过入口UIAbility组件启动收付款UIAbility组件。
  • 应用间的交互:当前应用可以启动其他应用,来完成某个任务或操作。比如,启动浏览器应用来打开网站、启动文件应用来浏览或编辑文件等。
  • 应用的跨设备流转:通过应用的跨端迁移和多端协同,获得更好的使用体验。比如,在平板上播放的视频,迁移到智慧屏继续播放。
  • 在应用使用场景中,当用户在应用内点击某个按钮时,经常需要拉起指定UIAbility组件来完成某些特定任务。在启动UIAbility时,指定了abilityName和bundleName参数,可以使用显式Want方式启动UIAbility。

2.监听系统环境变量的变化

下面以监听系统环境变量的变化的开发场景为例,介绍AbilityStage组件回调函数的使用。

  • 在onCreate()生命周期中,通过EnvironmentCallback来监听系统环境变化,例如系统语言、深浅色模式、屏幕方向、字体大小缩放比例、字体粗细缩放比例等信息。

  • 当系统全局配置发生变更时,会触发EnvironmentCallback中的onConfigurationUpdated()回调,并打印相关信息。

  • 通过关闭应用进程,可以触发AbilityStage的onDestroy()生命周期回调。

    ts 复制代码
    import { EnvironmentCallback, AbilityStage } from '@kit.AbilityKit';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    export default class MyAbilityStage extends AbilityStage {
      onCreate(): void {
        console.log('AbilityStage onCreate');
        let envCallback: EnvironmentCallback = {
          onConfigurationUpdated(config) {
            console.info(`envCallback onConfigurationUpdated success: ${JSON.stringify(config)}`);
            let language = config.language; //应用程序的当前语言
            let colorMode = config.colorMode; //深浅色模式
            let direction = config.direction; //屏幕方向
            let fontSizeScale = config.fontSizeScale; //字体大小缩放比例
            let fontWeightScale = config.fontWeightScale; //字体粗细缩放比例
          },
          onMemoryLevel(level) {
            console.log(`onMemoryLevel level: ${level}`);
          }
        };
        try {
          let applicationContext = this.context.getApplicationContext();
          let callbackId = applicationContext.on('environment', envCallback);
          console.log(`callbackId: ${callbackId}`);
        } catch (paramError) {
          console.error(`error: ${(paramError as BusinessError).code}, ${(paramError as BusinessError).message}`);
        }
      }
    
      onDestroy(): void {
        // 通过onDestroy()方法,可以监听到Ability的销毁事件。
        console.log('AbilityStage onDestroy');
      }
    }

3.UIAbility备份恢复

场景介绍

当应用后台运行时,可能由于系统资源管控等原因导致应用关闭、进程退出,应用直接退出可能会导致用户数据丢失。如果应用在UIAbilityContext中启用了UIAbility备份恢复功能,并对临时数据进行保存,则可以在应用退出后的下一次启动时恢复先前的状态和数据(包括应用的页面栈以及onSaveState接口中保存的数据),从而保证用户体验的连贯性。

说明:

应用正常关闭时,不会触发UIAbility备份流程。应用正常启动(例如通过startAbility接口启动或点击图标启动),不触发UIAbility恢复流程。

运行机制
  • UIAbility数据备份:在应用的onBackground生命周期后,系统自动调用onSaveState进行备份。
  • UIAbility数据恢复:恢复的Want数据可以在应用的onCreate生命周期中获取,页面栈数据在应用的onWindowStageCreate生命周期中恢复。
约束限制
  • UIAbility备份恢复支持多实例,备份数据保存7天,以文件的形式存储在应用的沙箱路径中。

  • 备份数据以WantParams形式存储,由于序列化大小限制,支持的最大数据量为200KB。

  • 重启设备不支持还原备份。UIExtensionAbility不支持备份恢复。

接口说明

UIAbility备份恢复接口由UIAbilityContext模块提供,开发者可以通过在UIAbility中通过this.context直接调用,

接口名称 说明
setRestoreEnabled(enabled: boolean): void 设置当UIAbility从后台切换回时是否启用恢复。

setRestoreEnabled: 需要在应用初始化阶段调用(onForeground前),比如UIAbility的onCreate调用。

开发步骤

开发者需要在应用模块初始化时启用UIAbility备份恢复功能。

ts 复制代码
import { UIAbility } from '@kit.AbilityKit';

export default class EntryAbility extends UIAbility {
    onCreate() {
        console.info("[Demo] EntryAbility onCreate");
        this.context.setRestoreEnabled(true);
    }
}

开发者主动保存数据,在UIAbility启动时恢复。

ts 复制代码
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';

export default class EntryAbility extends UIAbility {
    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
        console.info("[Demo] EntryAbility onCreate");
        this.context.setRestoreEnabled(true);
        if (want && want.parameters) {
          let recoveryMyData = want.parameters["myData"];
        }
    }

    onSaveState(state:AbilityConstant.StateType, wantParams: Record<string, Object>) {
        // Ability has called to save app data
        console.log("[Demo] EntryAbility onSaveState");
        wantParams["myData"] = "my1234567";
        return AbilityConstant.OnSaveResult.ALL_AGREE;
    }
}

4.获取应用异常退出原因

当应用异常退出后再次启动时,开发者往往需要获取上次异常退出的具体原因和当时的应用状态信息,比如应用内存占用的rss、pss值、上次应用退出的时间等等。通过UIAbility和UIExtensionAbility的OnCreate生命周期函数中的launchParam参数,开发者可以获取到相关信息,并将其应用于应用体验的分析改进,从而调整业务逻辑、提高应用的存活率。
仅UIAbility和UIExtensionAbility支持获取上次的退出原因。

接口说明
接口名 描述
LaunchParam 启动参数。此接口的lastExitReason、lastExitMessage、lastExitDetailInfo成员记录Ability上次异常退出的信息。
LastExitDetailInfo 最后退出时的进程状态和详细原因。
开发步骤
  1. 获取UIAbility上次退出的原因。

    在UIAbility类的OnCreate成员函数的launchParam参数中读取Ability上次退出的信息。

    ts 复制代码
    import { UIAbility, Want, AbilityConstant } from '@kit.AbilityKit';
    
    const MAX_RSS_THRESHOLD: number = 100000;
    const MAX_PSS_THRESHOLD: number = 100000;
    
    function doSomething() {
      console.log('do Something');
    }
    
    function doAnotherThing() {
      console.log('do Another Thing');
    }
    
    class MyAbility extends UIAbility {
      onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
        // 获取退出原因
        let reason: number = launchParam.lastExitReason;
        let subReason: number = -1;
        if (launchParam.lastExitDetailInfo) {
          subReason = launchParam.lastExitDetailInfo.exitSubReason;
        }
        let exitMsg: string = launchParam.lastExitMessage;
    
        if (launchParam.lastExitDetailInfo) {
          // 获取Ability上次退出时所在进程的信息
          let pid = launchParam.lastExitDetailInfo.pid;
          let processName: string = launchParam.lastExitDetailInfo.processName;
          let rss: number = launchParam.lastExitDetailInfo.rss;
          let pss: number = launchParam.lastExitDetailInfo.pss;
          // 其他信息
          let uid: number = launchParam.lastExitDetailInfo.uid;
          let timestamp: number = launchParam.lastExitDetailInfo.timestamp;
        }
      }
    }
  2. 根据上次退出的信息做相应的业务处理。

    • 对于不同的退出原因,开发者可以增加不同的处理逻辑,例如:
    ts 复制代码
    if (reason === AbilityConstant.LastExitReason.APP_FREEZE) {
        // Ability上次因无响应而退出,此处可增加处理逻辑。
        doSomething();
    } else if (reason === AbilityConstant.LastExitReason.SIGNAL && subReason === 9) {
        // Ability上次所在进程因kill -9信号而退出,此处可增加处理逻辑。
        doAnotherThing();
    } else if (reason === AbilityConstant.LastExitReason.RESOURCE_CONTROL) {
        // Ability上次因rss管控而退出,此处可实现处理逻辑,最简单的就是打印出来。
        console.log('The ability has exit last because the rss control,the lastExitReason is '+  reason + 
        ', subReason is ' + subReason + ', lastExitMessage is ' + exitMsg);
    }
    • 根据进程信息感知应用内存占用异常,例如:
    ts 复制代码
    if (rss > MAX_RSS_THRESHOLD || pss > MAX_PSS_THRESHOLD) {
        // RSS或PSS值过大,说明内存使用率接近或达到上限,打印告警,或者增加处理逻辑。
        console.warn('Process ' + processName + '(' + pid + ') memory usage approaches or reaches the upper limit.');
    }
    • 根据异常退出时刻的时间戳,明确异常发生的时刻,便于问题定位。
    ts 复制代码
    console.log('App ' + uid + ' terminated at ' + timestamp);

AbilityStage 是 OpenHarmony 中Module级生命周期总线,在首次加载 Module 时唯一实例化,负责初始化、环境监听、进程分流、异常恢复等底层工作;搭配 UIAbility 的备份/恢复与退出原因诊断接口,可让应用在被杀->重启->恢复等过程保持用户现场,是开发高可靠多设备应用的隐形引擎

相关推荐
Damon小智4 小时前
RedPlayer 视频播放器在 HarmonyOS 应用中的实践
音视频·harmonyos·鸿蒙·小红书·三方库·redplayer
猫林老师15 小时前
HarmonyOS分布式硬件共享:调用手机摄像头的手表应用
华为·交互·harmonyos
前端世界19 小时前
HarmonyOS应用开发指南:Toast无法显示的完整排查流程与实战案例
华为·harmonyos
安卓开发者1 天前
鸿蒙NEXT Wear Engine穿戴侧应用开发完全指南
ubuntu·华为·harmonyos
安卓开发者1 天前
鸿蒙Next振动开发指南:打造沉浸式触觉反馈体验
华为·harmonyos
Devil枫1 天前
HarmonyOS屏幕方向适配指南
华为·harmonyos
li理1 天前
鸿蒙Image Kit深度解析:从图片解码到高级特效处理
harmonyos
li理1 天前
鸿蒙相机开发中篇:自定义 UI 与拍摄控制
harmonyos
鸿蒙小白龙1 天前
OpenHarmony 与 HarmonyOS 的 NAPI 开发实战对比:自上而下与自下而上的差异解析
harmonyos·鸿蒙·鸿蒙系统·open harmony