鸿蒙开发5.0【应用启动框架AppStartup应用场景分析】

启动框架应用场景

大型应用在启动过程中会加载大量的模块或SDK,各个模块或SDK还有依赖,模块或SDK加载要有一套管理机制,否则会杂乱无章,都耦合在一起,进而会影响启动性能。

AppStartup提供在应用启动时初始化组件的简单而高效的方法。

  1. 更好管理应用程序初始化过程,避免出现初始化错误、重复初始化等问题。
  2. 提高应用程序的启动速度和用户体验。

启动流程介绍(自动模式)

自动模式下启动框架的执行顺序在创建AbilityStage和执行AbilityStage onCreate回调之间。

那启动框架内的任务执行顺序是什么样子呢? 基于以下配置,进行任务时序分析。

注意:

  1. configEntry是启动框架初始化组件的全局配置入口函数。主要包括 【执行所有组件初始化的超时时间】 和 【表示启动框架的监听器,该监听器将在所有组件初始化完成时调用】。
  2. startupTasks配置中的 srcEntry 表示 需要加载的组件实现的入口函数。

以下是startup_config.json文件中的配置。

{
  "startupTasks": [
  {
    "name": "StartupTask_001",
    "srcEntry": "./ets/Startup2/StartupTask_001.ets",
    "dependencies": []
  },
  {
    "name": "StartupTask_002",
    "srcEntry": "./ets/Startup2/StartupTask_002.ets",
    "dependencies": [
      "StartupTask_001"
    ]
  }
  ],
  "configEntry": "./ets/Startup2/StartupConfig.ets"
}

1

场景以及解决方案

场景介绍

在开发应用的时候,一般都会引入SDK,而大部分SDK都要求我们在Application启动前初始化,当我们引入的SDK越来越多,就会出现Application启动时间越来越长,如果SDK的初始化任务相互依赖,还要处理很多条件判断。如果都在主线程按照顺序初始化,或者再加上异步初始化。那APP的启动性能就会非常差。

举例: xx银行应用初始化模块加载,广告模块、人脸识别模块、APM模块、配置中心模块、数据管理模块、静态配置模块、H5灰度模块、首页加载模块、启动模块、定位模块、日志模块、登录模块、网络模块、离线模块、弹屏模块、隐私模块、推送模块、路由模块、安全模块、埋点模块、音视频模块、银联支付模块、url安全校验模块、用户中心模块、设备管理模块、X5初始化模块。

优势:减少手动加载的错误率。

配置启动框架AppStartup,应用启动时初始化组件。

SDK/组件/任务 依赖关系 如下图所示:

2

最终发现组件的加载顺序为:1->2->4->3->5。

3

应用步骤配置以及介绍

启动框架手动配置

其他步骤同自动配置步骤一样,不同点是需要改动startup_config.json配置项excludeFromAutoStart为true。然后在EntryAbility的onCreate钩子函数手动执行任务。

  1. 修改启动框架配置文件startup_config.json添加初始化组件。

    [
      {
        "name": "StartupTask_00C",
        "srcEntry": "./ets/Startup1/StartupTask_00C.ets",
        "dependencies": [
          "StartupTask_00A",
          "StartupTask_00B"
        ],
        "runOnThread": "mainThread",
        "waitOnMainThread": false,
        "excludeFromAutoStart": true
      }
    ...
    ]
    

    依赖关系如下图所示:

    4

  2. 在EntryAbility的onCreate钩子函数调用startupManager.run()。

    import startupManager from '@ohos.app.appstartup.startupManager';
    
    export default class EntryAbility extends UIAbility {
      onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
        let startParams = ['StartupTask_00C'];
        try {
          startupManager.run(startParams).then(() => {
            console.log('StartupTest startupManager run then, startParams');
          }).catch((error: BusinessError) => {
            console.info("StartupTest promise catch error, error" + JSON.stringify(error));
            console.info("StartupTest promise catch error, startParams"
              + JSON.stringify(startParams));
          })
        } catch (error) {
          let errMsg = JSON.stringify(error);
          let errCode: number = error.code;
          console.log('Startup catch error , errCode' + errCode);
          console.log('Startup catch error ,error' + errMsg);
        }
      }
      ...
    }
    
  3. 加载结果。

    5

场景二:超时场景分析

场景介绍

从启动框架配置文件StartupConfig.ets可知,启动框架配置需要在StartupConfigEntry中设置StartupConfig与StartupListener。如下图所示:

6

当SDK加载超时(组件实际加载时间 > 设置的超时时间)之后,就会造成APP启动异常。

实现代码

  1. 设置超时时间,如上图所示,设置500ms超时时间。

  2. 在 StartupTask_001的初始化回调函数中,等待2s。

    7

结果分析及解决

可以看到,启动框架组件初始化异常报错,且APP也无法正常启动。

8

超时时间设置过短,APP启动异常;超时时间设置过长,又不符合正常APP启动组件加载逻辑,那么该如何正确设置超时时间呢?

那么就分析所有组件加载的时间,根据业务需求设置一个最合适的启动框架超时加载时间。那又如何去进行组件加载的耗时统计分析呢?请参考场景三。

场景三:耗时统计分析

场景介绍

对于加载大量模块(SDK), CPU、网络、异常、音视频模块、广告模块、日志模块、推送模块等 都可能成为系统的性能瓶颈。那APP加载对于不同模块依赖做耗时统计分析,就成为性能调优的一个必要手段。

针对不同模块的加载或任务处理,利用StartupConfigEntry文件中配置的超时时间以及组件初始化的监听器,结合启动框架中支持的依赖回调指标做数据埋点,统计耗时组件加载。以统计StartupTask_001的加载时间为例,统计结果:

9

实现代码

  1. 由于我们添加启动框架配置时,StartupConfigEntry已经配置了超时时间和组件初始化的监听器,此步骤不再重复。

  2. 根据拓扑排序,我们可以知道组件间的加载顺序。

  3. 分析统计耗时场景,修改startup_config:

    {
      "startupTasks": [
      {
        "name": "StartupTask_002",
        "srcEntry": "./ets/Startup2/StartupTask_002.ets",
        "dependencies": [
          "StartupTask_001"
        ],
        "runOnThread": "mainThread",
        "waitOnMainThread": false
      },
      {
        "name": "StartupTask_001",
        "srcEntry": "./ets/Startup2/StartupTask_001.ets",
        "dependencies": [],
        "runOnThread": "mainThread",
        "waitOnMainThread": false
      }
      ],
      "configEntry": "./ets/Startup2/StartupConfig.ets"
    }
    
  4. 开始时间埋点。

    在任务1开始时记录开始时间。

    import StartupTask from '@ohos.app.appstartup.StartupTask';
    import common from '@ohos.app.ability.common';
    import hilog from '@ohos.hilog';
    
    interface TaskResult {
      taskName: string
      startRunTime?: number
    }
    
    export default class StartupTask_001 extends StartupTask {
        async init(context: common.AbilityStageContext): Promise<TaskResult> {
        this.startTime = new Date().getTime()
        hilog.info(0x0000, 'testTag', `StartupTask_001 init.  runtime_start: ${new Date().getTime()}`);
        await this.delay(2000)
        return {
          taskName:  'StartupTask_001',
          startRunTime:this.startTime
        };
      }
    }
    
  5. 结束时间埋点。

    在依赖加载结束后记录任务1的结束时间。此时 onDependencyCompleted参数result是任务1执行结束后返回的结果。

    import StartupTask from '@ohos.app.appstartup.StartupTask';
    import common from '@ohos.app.ability.common';
    import hilog from '@ohos.hilog';
    
    interface TaskResult {
      taskName: string
      startRunTime: number
    }
    
    export default class StartupTask_002 extends StartupTask {
    
      async init(context: common.AbilityStageContext) {
        hilog.info(0x0000, 'testTag', 'StartupTask_002 init.');
        return 'StartupTask_002';
      }
    
      onDependencyCompleted(dependence: string, result: TaskResult): void {
        const endRunTime = new Date().getTime()
        hilog.info(0x0000, 'ResultTag', `startRunTime: ${result.startRunTime} endRunTime: ${endRunTime}  total-time: ${endRunTime-result.startRunTime}`);
        hilog.info(0x0000, 'testTag', 'StartupTask_002 onDependencyCompleted, dependence: %{public}s, result: %{public}s',
          dependence, JSON.stringify(result));
      }
    }
    

常见问题

  1. 有向无环图(拓扑排序)

    有向无环图:在图论中,如果一个有向图从任意顶点出发无法经过若干条边回到该点,则这个图是一个有向无环图(DAG, Directed Acyclic Graph)。拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。且该序列必须满足下面两个条件:

    • 每个顶点出现且只出现一次。
    • 若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。

    10

    它是一个DAG图,那么如何写出它的拓扑排序呢?

    这里说一种比较常用的方法:从DAG图中选择一个没有前驱(即入度为 0)的顶点并输出。从图中删除该顶点和所有以它为起点的有向边,重复1和2直到当前的DAG图为空或当前图中不存在无前驱的顶点为止,后一种情况说明有向图中必然存在环。

    11

    于是,得到拓扑排序后的结果是 {1, 2, 4, 3, 5}。

  2. AppStartup的作用。

    AppStartup提供了一种更加简单高效的初始化组件的方式,支持异步初始化组件加速应用的启动时间。使用启动框架应用开发者只需要分别为待初始化的组件实现AppStartup提供的StartupTask接口,并在startup_config中配置AppStartup之间的依赖关系,启动框架将使用拓扑排序保证各个待初始化组件的初始化顺序。启动框架只支持在entry中使用。

以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
1

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下

内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

鸿蒙【北向应用开发+南向系统层开发】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经

2

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!
3

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值