UIAbility启动模式

什么是UIAbility? UIAbility组件是一种包含UI的应用组件,主要用于和用户交互 。它是HarmonyOS中用于系统调度的基本单元,为应用提供绘制界面的窗口。

其他官方专业数据就不赘述了,简单将就是手机应用里的一个UI窗口。这个类比Android里的Activity,都是UI的应用组件。

官方入口

开发者学堂入口

开发指南入口

基础理论

UIAbility类似Android中的Activity,Activity有4中启动模式,而UIAbility有3中启动模式。HarmonyOS中的UIAbility的启动模式相较于Android更加简化易于理解。

  • singleton(单实例模式)

当你给UIAbility的launchType设置为单实例模式,则无论你启动几次该窗口都将仅有一个窗口,多次启动后仅会进入该UIAbility的onNewWant()回调

  • multiton(多实例模式)

多实例模式也是标准模式(standard),标准模式就旧版称呼。多实例模式就是你启动几次UIAbility就会创建几个新的窗口。

  • specified(指定实例模式)

specified启动模式为指定实例模式,简单说就是自定义启动模式,是多实例还是单实例你自己来实现

实战说明

我们在刚刚新建的项目上右键创建一个新的UIAbility,起名为SingletonAbility,点击完成即可。

idea会自动生成一个名为SingletonAbility的文件,同时将该窗口配置到配置文件中。

同理我们在创建MultitonAbilitySpecifiedUIAbility,同时分别设置相应的launchType

...
"abilities": [
     ...
      {
        "name": "SingletonAbility",
        "srcEntry": "./ets/singletonability/SingletonAbility.ets",
        "description": "$string:SingletonAbility_desc",
        "icon": "$media:layered_image",
        "label": "$string:SingletonAbility_label",
        "launchType": "singleton",  // 重点这里
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background"
      },
      {
        "name": "MultitonAbility",
        "srcEntry": "./ets/multitonability/MultitonAbility.ets",
        "description": "$string:MultitonAbility_desc",
        "icon": "$media:layered_image",
        "label": "$string:MultitonAbility_label",
        "launchType": "multiton",  // 重点这里
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background"
      },
      {
        "name": "SpecifiedAbility",
        "srcEntry": "./ets/specifiedability/SpecifiedAbility.ets",
        "description": "$string:SpecifiedAbility_desc",
        "icon": "$media:layered_image",
        "launchType": "specified",  // 重点这里
        "label": "$string:SpecifiedAbility_label",
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background"
      }
    ],
...

默认工程指定入口窗口EntryUIAbility使用的是pages/Index.etx的启动页面,我们在这个页面增加几个按钮实现跳转,这样准备工作基本完成。

@Entry
@Component
struct Index {
  build() {
    Column() {
      Button("打开单实例窗口")
        .onClick(() => {
          let context = getContext(this) as common.UIAbilityContext
          let want: Want = {
            bundleName: 'com.byrain.example_001',
            abilityName: 'SingletonAbility'
          };
          context.startAbility(want);
        })
      Button("打开多实例窗口")
        .onClick(() => {
          let context = getContext(this) as common.UIAbilityContext
          let want: Want = {
            bundleName: 'com.byrain.example_001',
            abilityName: 'MultitonAbility'
          };
          context.startAbility(want);
        })
      ... // 指定启动模式下面单独说
    }
    .height('100%')
    .width('100%')
  }
}

几个UIAbility使用的page都是Index.ets,所以界面都是一样的,现在启动应用,

单实例验证

点击打开单实例,会打开新页面,在新页面再次点击打开单实例界面没有反应。我们看日志

02-21 16:07:08.592   13468-13468   A00000/testTag                  pid-13468             I     EntryAbility onCreate
02-21 16:07:08.644   13468-13468   A00000/testTag                  pid-13468             I     EntryAbility onWindowStageCreate
02-21 16:07:08.654   13468-13468   A00000/testTag                  pid-13468             I     EntryAbility onForeground
02-21 16:07:08.710   13468-13468   A00000/testTag                  pid-13468             I     Succeeded in loading the content.
02-21 16:08:08.640   13468-13468   A00000/testTag                  com.byrai...mple_001  I     EntryAbility onBackground
02-21 16:08:08.688   13468-13468   A00000/testTag                  com.byrai...mple_001  I     SingletonAbility onCreate
02-21 16:08:08.717   13468-13468   A00000/testTag                  com.byrai...mple_001  I     SingletonAbility onWindowStageCreate
02-21 16:08:08.730   13468-13468   A00000/testTag                  com.byrai...mple_001  I     SingletonAbility onForeground
02-21 16:08:08.768   13468-13468   A00000/testTag                  com.byrai...mple_001  I     Succeeded in loading the content.
02-21 16:08:10.499   13468-13468   A00000/testTag                  com.byrai...mple_001  I     SingletonAbility onNewWant
02-21 16:08:11.722   13468-13468   A00000/testTag                  com.byrai...mple_001  I     SingletonAbility onNewWant

第一次打开单例窗口后,UIAbility创建新实例,再次单击打开时候则进入onNewWant()回调,当前窗口仅创建一个。

我们通过aa工具查看也确实仅有两个UIAbility

$ aa dump -l
User ID #100
  current mission lists:{
    Mission ID #136  mission name #[#com.byrain.example_001:entry:EntryAbility]  lockedState #0  mission affinity #[]
      AbilityRecord ID #1725
        app name [com.byrain.example_001]
        main name [EntryAbility]
        bundle name [com.byrain.example_001]
        ability type [PAGE]
        state #BACKGROUND  start time [98914947]
        app state #FOREGROUND
        ready #1  window attached #0  launcher #0
        callee connections:
        isKeepAlive: false
 }
    Mission ID #137  mission name #[#com.byrain.example_001:entry:SingletonAbility]  lockedState #0  mission affinity #[]
      AbilityRecord ID #1727
        app name [com.byrain.example_001]
        main name [SingletonAbility]
        bundle name [com.byrain.example_001]
        ability type [PAGE]
        state #FOREGROUND  start time [98975152]
        app state #FOREGROUND
        ready #1  window attached #0  launcher #0
        callee connections:
        isKeepAlive: false
 }

多实例验证

我们结束进程,然后从新打开应用,点击打开多实例此时会打开新页面,在新页面点击打开多实例会再次打开个新页面。我们看日志执行

02-21 16:20:32.147   16786-16786   A00000/testTag                  com.byrai...mple_001  I     EntryAbility onCreate
02-21 16:20:32.170   16786-16786   A00000/testTag                  com.byrai...mple_001  I     EntryAbility onWindowStageCreate
02-21 16:20:32.179   16786-16786   A00000/testTag                  com.byrai...mple_001  I     EntryAbility onForeground
02-21 16:20:32.217   16786-16786   A00000/testTag                  com.byrai...mple_001  I     Succeeded in loading the content.
02-21 16:20:34.117   16786-16786   A00000/testTag                  com.byrai...mple_001  I     EntryAbility onBackground
02-21 16:20:34.126   16786-16786   A00000/testTag                  com.byrai...mple_001  I     MultitonAbility onCreate
02-21 16:20:34.147   16786-16786   A00000/testTag                  com.byrai...mple_001  I     MultitonAbility onWindowStageCreate
02-21 16:20:34.153   16786-16786   A00000/testTag                  com.byrai...mple_001  I     MultitonAbility onForeground
02-21 16:20:34.188   16786-16786   A00000/testTag                  com.byrai...mple_001  I     Succeeded in loading the content.
02-21 16:20:36.328   16786-16786   A00000/testTag                  com.byrai...mple_001  I     MultitonAbility onBackground
02-21 16:20:36.332   16786-16786   A00000/testTag                  com.byrai...mple_001  I     MultitonAbility onCreate
02-21 16:20:36.339   16786-16786   A00000/testTag                  com.byrai...mple_001  I     MultitonAbility onWindowStageCreate
02-21 16:20:36.345   16786-16786   A00000/testTag                  com.byrai...mple_001  I     MultitonAbility onForeground
02-21 16:20:36.374   16786-16786   A00000/testTag                  com.byrai...mple_001  I     Succeeded in loading the content.
02-21 16:20:38.631   16786-16786   A00000/testTag                  com.byrai...mple_001  I     MultitonAbility onCreate
02-21 16:20:38.647   16786-16786   A00000/testTag                  com.byrai...mple_001  I     MultitonAbility onWindowStageCreate
02-21 16:20:38.663   16786-16786   A00000/testTag                  com.byrai...mple_001  I     MultitonAbility onForeground
02-21 16:20:38.663   16786-16786   A00000/testTag                  com.byrai...mple_001  I     MultitonAbility onBackground
02-21 16:20:38.684   16786-16786   A00000/testTag                  com.byrai...mple_001  I     Succeeded in loading the content.

每次打开都会创建一个新的UIAbility实例,通过aa工具也可以看到有4个UIAbility。

$ aa dump -l
User ID #100
  current mission lists:{
    Mission ID #138  mission name #[#com.byrain.example_001:entry:EntryAbility]  lockedState #0  mission affinity #[]
      AbilityRecord ID #1740
        app name [com.byrain.example_001]
        main name [EntryAbility]
        bundle name [com.byrain.example_001]
        ability type [PAGE]
        state #BACKGROUND  start time [99718497]
        app state #FOREGROUND
        ready #1  window attached #0  launcher #0
        callee connections:
        isKeepAlive: false
 }
    Mission ID #139  mission name #[#com.byrain.example_001:entry:MultitonAbility]  lockedState #0  mission affinity #[]
      AbilityRecord ID #1741
        app name [com.byrain.example_001]
        main name [MultitonAbility]
        bundle name [com.byrain.example_001]
        ability type [PAGE]
        state #BACKGROUND  start time [99720633]
        app state #FOREGROUND
        ready #1  window attached #0  launcher #0
        callee connections:
        isKeepAlive: false
 }
    Mission ID #140  mission name #[#com.byrain.example_001:entry:MultitonAbility]  lockedState #0  mission affinity #[]
      AbilityRecord ID #1742
        app name [com.byrain.example_001]
        main name [MultitonAbility]
        bundle name [com.byrain.example_001]
        ability type [PAGE]
        state #BACKGROUND  start time [99722839]
        app state #FOREGROUND
        ready #1  window attached #0  launcher #0
        callee connections:
        isKeepAlive: false
 }
    Mission ID #141  mission name #[#com.byrain.example_001:entry:MultitonAbility]  lockedState #0  mission affinity #[]
      AbilityRecord ID #1743
        app name [com.byrain.example_001]
        main name [MultitonAbility]
        bundle name [com.byrain.example_001]
        ability type [PAGE]
        state #FOREGROUND  start time [99725149]
        app state #FOREGROUND
        ready #1  window attached #0  launcher #0
        callee connections:
        isKeepAlive: false
 }

指定启动模式验证

指定启动模式是自定义页面启动模式,所以不是简单配置后直接调用startAbility,这里需要介绍下AbilityStage

AbilityStage类似Android里的Application,AbilityStage是HarmonyOS中Stage模型的一个核心组件,用于管理应用的生命周期和状态。这里我们主要使用AbilityStageonAcceptWant的生命周期回调,判断指定启动模式的UIAbility是否是单实例主要在这个回调中处理。

我们在Index.etx中增加启动指定启动模式的按钮,在启动时候传入的Want(下一篇介绍)并在其属性parameters中指定参数

 Button("打开指定模式为单实例窗口")
        .onClick(() => {
          let context = getContext(this) as common.UIAbilityContext
          let want: Want = {
            bundleName: 'com.byrain.example_001',
            abilityName: 'SpecifiedAbility',
            parameters: {
              type: 1
            }
          };
          context.startAbility(want);
        })
  Button("打开指定模式为多实例窗口")
    .onClick(() => {
      let context = getContext(this) as common.UIAbilityContext
      let num = LocalStorage.getShared().get("type") as number
      if (num == undefined) {
        num = 1;
      }
      num = num + 1;
      hilog.info(0x0000, 'testTag', '%{public}s', `启动页面类型值${num}`);
      let want: Want = {
        bundleName: 'com.byrain.example_001',
        abilityName: 'SpecifiedAbility',
        parameters: {
          type: num
        }
      };
      context.startAbility(want);
    })

然后我们自定义AbilityStage,实现onAcceptWant回调,在这里根据want参数返回字符串

export default class Example_001AbilityStage extends AbilityStage {
  onAcceptWant(want: Want): string {
    // 这里的want可以接收startAbility时候传入的want参数
    if (want.abilityName === 'SpecifiedAbility' && want.parameters) {
      // 如果跳转的UIAbility是指定启动模式的UIAbility则根据参数type返回不同的字符串,
      // 如果每次返回相同的字符串,则代表启动的是单实例UIAbility。这里返回的字符串是UIAbility的唯一标识
      if (want.parameters.type) {
        hilog.info(0x0000, 'testTag', '%{public}s', `接收到的指定启动模式的参数值${want.parameters.type}`);
        return `SpecifiedAbility${want.parameters.type}`
      }
    }
    return super.onAcceptWant(want)
  }
}

我们重新启动应用,点击打开指定模式为单实例窗口,在打开的新页面再次点击,看日志:

02-21 16:42:27.312   21526-21526   A00000/testTag                  com.byrai...mple_001  I     EntryAbility onCreate
02-21 16:42:27.324   21526-21526   A00000/testTag                  com.byrai...mple_001  I     EntryAbility onWindowStageCreate
02-21 16:42:27.332   21526-21526   A00000/testTag                  com.byrai...mple_001  I     EntryAbility onForeground
02-21 16:42:27.371   21526-21526   A00000/testTag                  com.byrai...mple_001  I     Succeeded in loading the content.
02-21 16:42:29.036   21526-21526   A00000/testTag                  com.byrai...mple_001  I     接收到的指定启动模式的参数值1
02-21 16:42:29.063   21526-21526   A00000/testTag                  com.byrai...mple_001  I     EntryAbility onBackground
02-21 16:42:29.071   21526-21526   A00000/testTag                  com.byrai...mple_001  I     SpecifiedAbility onCreate
02-21 16:42:29.076   21526-21526   A00000/testTag                  com.byrai...mple_001  I     specifiedability onWindowStageCreate
02-21 16:42:29.079   21526-21526   A00000/testTag                  com.byrai...mple_001  I     SpecifiedAbility onForeground
02-21 16:42:29.098   21526-21526   A00000/testTag                  com.byrai...mple_001  I     Succeeded in loading the content.
02-21 16:42:30.027   21526-21526   A00000/testTag                  com.byrai...mple_001  I     接收到的指定启动模式的参数值1
02-21 16:42:30.032   21526-21526   A00000/testTag                  com.byrai...mple_001  I     SpecifiedAbility onNewWant
02-21 16:42:30.693   21526-21526   A00000/testTag                  com.byrai...mple_001  I     接收到的指定启动模式的参数值1
02-21 16:42:30.701   21526-21526   A00000/testTag                  com.byrai...mple_001  I     SpecifiedAbility onNewWant

可以看到后面再次启动时候则走的SpecifiedAbility回调onNewWant,通过aa工具查看,只有2个UIAbility

$ aa dump -l
User ID #100
  current mission lists:{
    Mission ID #142  mission name #[#com.byrain.example_001:entry:EntryAbility]  lockedState #0  mission affinity #[]
      AbilityRecord ID #1765
        app name [com.byrain.example_001]
        main name [EntryAbility]
        bundle name [com.byrain.example_001]
        ability type [PAGE]
        state #BACKGROUND  start time [101033688]
        app state #FOREGROUND
        ready #1  window attached #0  launcher #0
        callee connections:
        isKeepAlive: false
 }
    Mission ID #143  mission name #[#com.byrain.example_001:entry:SpecifiedAbility]  lockedState #0  mission affinity #[]
      AbilityRecord ID #1766
        app name [com.byrain.example_001]
        main name [SpecifiedAbility]
        bundle name [com.byrain.example_001]
        ability type [PAGE]
        state #FOREGROUND  start time [101035574]
        app state #FOREGROUND
        ready #1  window attached #0  launcher #0
        callee connections:
        isKeepAlive: false
 }

我们再次重新启动应用,点击打开指定模式为多实例窗口,在打开的新页面再次点击,看日志:

02-21 16:52:12.299   23949-23949   A00000/testTag                  pid-23949             I     EntryAbility onCreate
02-21 16:52:12.314   23949-23949   A00000/testTag                  com.byrai...mple_001  I     EntryAbility onWindowStageCreate
02-21 16:52:12.329   23949-23949   A00000/testTag                  com.byrai...mple_001  I     EntryAbility onForeground
02-21 16:52:12.374   23949-23949   A00000/testTag                  com.byrai...mple_001  I     Succeeded in loading the content.
02-21 16:52:14.130   23949-23949   A00000/testTag                  com.byrai...mple_001  I     启动页面类型值2
02-21 16:52:14.136   23949-23949   A00000/testTag                  com.byrai...mple_001  I     接收到的指定启动模式的参数值2
02-21 16:52:14.161   23949-23949   A00000/testTag                  com.byrai...mple_001  I     EntryAbility onBackground
02-21 16:52:14.167   23949-23949   A00000/testTag                  com.byrai...mple_001  I     SpecifiedAbility onCreate
02-21 16:52:14.179   23949-23949   A00000/testTag                  com.byrai...mple_001  I     specifiedability onWindowStageCreate
02-21 16:52:14.182   23949-23949   A00000/testTag                  com.byrai...mple_001  I     SpecifiedAbility onForeground
02-21 16:52:14.199   23949-23949   A00000/testTag                  com.byrai...mple_001  I     Succeeded in loading the content.
02-21 16:52:15.209   23949-23949   A00000/testTag                  com.byrai...mple_001  I     启动页面类型值3
02-21 16:52:15.213   23949-23949   A00000/testTag                  com.byrai...mple_001  I     接收到的指定启动模式的参数值3
02-21 16:52:15.234   23949-23949   A00000/testTag                  com.byrai...mple_001  I     SpecifiedAbility onBackground
02-21 16:52:15.247   23949-23949   A00000/testTag                  com.byrai...mple_001  I     SpecifiedAbility onCreate
02-21 16:52:15.254   23949-23949   A00000/testTag                  com.byrai...mple_001  I     specifiedability onWindowStageCreate
02-21 16:52:15.256   23949-23949   A00000/testTag                  com.byrai...mple_001  I     SpecifiedAbility onForeground
02-21 16:52:15.293   23949-23949   A00000/testTag                  com.byrai...mple_001  I     Succeeded in loading the content.

同样启动SpecifiedAbility,这时每次点击都会创建一个新实例,aa查看有3个UIAbility实例

$ aa dump -l
User ID #100
  current mission lists:{
    Mission ID #144  mission name #[#com.byrain.example_001:entry:EntryAbility]  lockedState #0  mission affinity #[]
      AbilityRecord ID #1777
        app name [com.byrain.example_001]
        main name [EntryAbility]
        bundle name [com.byrain.example_001]
        ability type [PAGE]
        state #BACKGROUND  start time [101618688]
        app state #FOREGROUND
        ready #1  window attached #0  launcher #0
        callee connections:
        isKeepAlive: false
 }
    Mission ID #145  mission name #[#com.byrain.example_001:entry:SpecifiedAbility]  lockedState #0  mission affinity #[]
      AbilityRecord ID #1778
        app name [com.byrain.example_001]
        main name [SpecifiedAbility]
        bundle name [com.byrain.example_001]
        ability type [PAGE]
        state #BACKGROUND  start time [101620679]
        app state #FOREGROUND
        ready #1  window attached #0  launcher #0
        callee connections:
        isKeepAlive: false
 }
    Mission ID #146  mission name #[#com.byrain.example_001:entry:SpecifiedAbility]  lockedState #0  mission affinity #[]
      AbilityRecord ID #1779
        app name [com.byrain.example_001]
        main name [SpecifiedAbility]
        bundle name [com.byrain.example_001]
        ability type [PAGE]
        state #FOREGROUND  start time [101621751]
        app state #FOREGROUND
        ready #1  window attached #0  launcher #0
        callee connections:
        isKeepAlive: false
 }

以上就是UIAbility启动模式介绍,欢迎点赞、关注+收藏

posted @ 2025-02-24 14:27 拜雨 阅读(3) 评论(0) 推荐(0) 编辑
摘要: UIAbility生命周期 什么是UIAbility? UIAbility组件是一种包含UI的应用组件,主要用于和用户交互 。它是HarmonyOS中用于系统调度的基本单元,为应用提供绘制界面的窗口。 其他官方专业数据就不赘述了,简单将就是手机应用里的一个UI窗口。这个类比Android里的Acti 阅读全文 »
posted @ 2025-02-21 16:59 拜雨 阅读(7) 评论(0) 推荐(0) 编辑
摘要: 如何在Kotlinx序列化中对BigDecimal和BigInteger进行JSON编码而不损失精度? 按着这里大佬的回答可以解决。但是有一点需要注意 我使用最新的kotlinx-serialization-json 1.8.0, idea在编译时候private object BigDecimal 阅读全文 »
posted @ 2025-01-17 14:31 拜雨 阅读(12) 评论(0) 推荐(0) 编辑
摘要: 我在Android8.0上增加的截屏功能,也声明了响应权限,但是在Android11上就报权限错误。原来在Android10以后启动前台服务时候有第三个参数。 低版本我们调用 public final void startForeground(int id, Notification notific 阅读全文 »
posted @ 2024-12-10 11:27 拜雨 阅读(286) 评论(0) 推荐(0) 编辑
摘要: 常量定义 在HarmonyOS中我们如果定义常量,可以创建常量类并导出,通过static readonly修饰。 export class ApiConst{ /** * api根路径 */ static readonly BASE_API: string = "http://192.168.100 阅读全文 »
posted @ 2024-12-09 16:48 拜雨 阅读(23) 评论(0) 推荐(0) 编辑
摘要: 预览 Harmony开发和Compose类似,在组件上增加@Preview后则可以在预览面板上看到UI效果。 组件预览 我们新建一个组件,该组件仅展示一个文本内容。 @Component export struct HelloComponent { @State message: string = 阅读全文 »
posted @ 2024-11-27 16:33 拜雨 阅读(10) 评论(0) 推荐(0) 编辑
摘要: 应用基本信息 我们先来看下harmony的工程结构中的文件 主要涉及以下几个目录 AppScope > app.json5:应用的全局配置信息,详见app.json5配置文件。 entry:HarmonyOS工程模块,编译构建生成一个HAP包。 src > main > ets:用于存放ArkTS源 阅读全文 »
posted @ 2024-11-27 14:03 拜雨 阅读(31) 评论(0) 推荐(0) 编辑
摘要: 1. Failed to get the device apiVersion 电脑长时间没关机,一直开着idea和模拟器,第三天运行时候就提示这个错误,无法安装。可以重启下hdc服务即可 hdc kill -r hdc start -r 2. DevEco Studio 无法连接真机 这个问题有很多 阅读全文 »
posted @ 2024-11-21 17:15 拜雨 阅读(24) 评论(0) 推荐(0) 编辑
摘要: 我在做Android开发时候使用到了百度人脸离线识别,需要依赖百度的库。他们的库是区分芯片的,而我们的产品既有高通的也有RK的,所以在我封装百度人脸时候会配置两个风味,例如下面: flavorDimensions = ['chip'] productFlavors { RkChip { dimens 阅读全文 »
posted @ 2024-11-20 11:30 拜雨 阅读(10) 评论(0) 推荐(0) 编辑
摘要: 现在HarmonyOS势头很猛,所以也学习下。。。 学习路线主要是按着官方网站推荐的路线。 视频课程HarmonyOS NEXT 。 开发文档开发指南 示例程序Codelabs、Sample 当然,对于没有开发经验的人来说,按着官方认证路线学习也是不错方案,官方提示初级、中级、高级的认证课程,完成课 阅读全文 »
posted @ 2024-11-19 16:45 拜雨 阅读(10) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示