Harmony应用开发基础-Ability框架

Ability框架的基础知识。

Ability框架

Ability

Ability是应用所具备能力的抽象,也是应用程序的重要组成部分。Ability可以分为FA(Feature Ability)和PA(Particle Ability)两种类型,每种类型为开发者提供了不同的模板,以便实现不同的业务功能。

FA支持Page Ability,PA支持Service Ability和Data Ability。

Page Ability

Page模板(以下简称“Page”)是FA唯一支持的模板,用于提供与用户交互的能力。一个Page可以由一个或多个AbilitySlice构成,AbilitySlice是指应用的单个页面及其控制逻辑的总和。

AbilitySlice路由配置

可以通过**addActionRoute()**方法为此AbilitySlice配置一条路由规则。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 在 MyAbility 中
public class MyAbility extends Ability {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
// set the main route
setMainRoute(MainSlice.class.getName());

// set the action route
addActionRoute("action.pay", PaySlice.class.getName());
addActionRoute("action.scan", ScanSlice.class.getName());
}
}

在 config.json 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"module": {
"abilities": [
{
"skills":[
{
"actions":[
"action.pay",
"action.scan"
]
}
]
...
}
]
...
}
...
}
  • 同一Page内导航

当发起导航的AbilitySlice和导航目标的AbilitySlice处于同一个Page时,可以通过present()方法实现导航。

如果开发者希望在用户从导航目标AbilitySlice返回时,能够获得其返回结果,则应当使用presentForResult()实现导航。用户从导航目标AbilitySlice返回时,系统将回调onResult()来接收和处理返回结果,开发者需要重写该方法。返回结果由导航目标AbilitySlice在其生命周期内通过setResult()进行设置。

  • 不同Page间导航

AbilitySlice作为Page的内部单元,以Action的形式对外暴露,因此可以通过配置Intent的Action导航到目标AbilitySlice。Page间的导航可以使用startAbility()或startAbilityForResult()方法,获得返回结果的回调为onAbilityResult()。在Ability中调用setResult()可以设置返回结果。

*跨设备迁移

在 HarmonyOS 中,分布式任务调度平台对搭载 HarmonysOS 的多设备构筑的“超级虚拟终端”提供统一的组件管理能力,为应用定义统一的能力极限、接口形式、数据结构、服务描述语言,屏蔽硬件差异;支持远程启动、远程调用、业务无缝迁移等分布式任务。

实现调度的约束与限制
  1. 远程调用 PA/FA,开发者需要在 Intent 中设置分布式的标记(例如:Intent.FLAG_ABILITYSLICE_DEVICE 表示该应用支持分布式调度),否则将无法获得分布式能力。

  2. 开发者可以通过 config.josn 中的 reqPermissions 字段里添加权限申请:

    1. 以获取跨设备链接的能力和分布式数据传输的权限。

      分布式数据传输的权限:

      {"name":"ohos.permission.servicebus.ACCESS_SERVICE"}
      三方应用使用权限:

      {"name":"ohos.permission.servicebus.DISTRIBUTED_DATASYNC"}
      系统应用使用权限:

      {"name":"ohos.huawei.hwddmp.servicebus.BIND_SERVICE"}

    2. 另外还有三个获取分布式设备信息需要的权限:

      "name":"ohos.permission.DISTURIBUTED_DEIVCE_STATE_CHANGE"
      "name":"ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"

      "name":"ohos.permission.GET_BUNEDLE_INFO"

      注意:还需要在Ability里主动声明需要用到的权限。

    3. FA(Feature Ability,Page模板的Ability)的调用支持启动和迁移行为,在进行调度时:

      1. 当启动FA时,需要开发者在Intent中指定对端设备的deviceIdbundleNameabilityName
      2. FA的迁移实现相同bundleNameabilityName的FA跨设备迁移,因此需要指定迁移设备的deviceId
    三类场景

    设备A(本地)、设备B(远端)。

      1. A 启动 B 的 FA
      2. A 的 FA 迁移至设备 B
      3. A 的 FA 迁移至设备 B,可主动撤回迁移。
    
    需要用到的接口
    1. 启动远程 FA

      startAbility(Intent intent) 接口提供启动指定设备上 FA 和 PA 的能力,Intent 指定带启动 FA 的设备 deviceIdbundleNameabilityName

    2. 迁移 FA

      continueAbility(String deviceId) 接口提供将本地 FA 迁移到指定设备上的能力。

      continueAbilityReversibly(String deviceId) 接口提供将本地 FA 迁移到指定设备上的能力,这种迁移可撤回,reverseContinueAbility() 接口提供撤回迁移的能力。

Service Ability

基于Service模板的Ability(以下简称“Service”)主要用于后台运行任务(如执行音乐播放、文件下载等),但不提供用户交互界面。Service可由其他应用或Ability启动,即使用户切换到其他应用,Service仍将在后台继续运行。

Service是单实例的。在一个设备上,相同的Service只会存在一个实例。

如果多个Ability共用这个实例,只有当与Service绑定的所有Ability都退出后,Service才能够退出。

由于Service是在主线程里执行的,因此,如果在Service里面的操作时间过长,开发者必须在Service里创建新的线程来处理(详见线程间通信),防止造成主线程阻塞,应用程序无响应。

创建 Serice

创建 service 很简单,只需要继承 Ability,然后在 config.json 中注册 service 即可。

  • onStart()

    该方法在创建Service的时候调用,用于Service的初始化。在Service的整个生命周期只会调用一次,调用时传入的Intent应为空。

  • onCommand()

    在Service创建完成之后调用,该方法在客户端每次启动该Service时都会调用,开发者可以在该方法中做一些调用统计、初始化类的操作。

  • onConnect()

    在Ability和Service连接时调用,该方法返回IRemoteObject对象,开发者可以在该回调函数中生成对应Service的IPC通信通道,以便Ability与Service交互。Ability可以多次连接同一个Service,系统会缓存该Service的IPC通信对象,只有第一个客户端连接Service时,系统才会调用Service的onConnect方法来生成IRemoteObject对象,而后系统会将同一个RemoteObject对象传递至其他连接同一个Service的所有客户端,而无需再次调用onConnect方法。

  • onDisconnect()

    在Ability与绑定的Service断开连接时调用。

  • onStop()

    在Service销毁时调用。Service应通过实现此方法来清理任何资源,如关闭线程、注册的侦听器等。

启动/停止 Service

Ability为开发者提供了startAbility()方法来启动另外一个Ability。因为Service也是Ability的一种,开发者同样可以通过将Intent传递给该方法来启动Service。不仅支持启动本地Service,还支持启动远程Service。启动 service 主要用于启动一个服务后台任务或者远程启动一个功能,不进行通信,不需要返回数据。 例如,设备A启动设备B,播放音乐。

开发者可以通过构造包含DeviceId、BundleName与AbilityName的Operation对象来设置目标Service信息。这三个参数的含义如下:

  • DeviceId:表示设备ID。如果是本地设备,则可以直接留空;如果是远程设备,可以通过ohos.distributedschedule.interwork.DeviceManager提供的getDeviceList()获取设备列表,详见Java API参考
  • BundleName:表示包名称。
  • AbilityName:表示待启动的Ability名称。

停止Service

Service一旦创建就会一直保持在后台运行,除非必须回收内存资源,否则系统不会停止或销毁Service。开发者可以在Service中通过terminateAbility()停止本Service或在其他Ability调用stopAbility()来停止Service。

停止Service同样支持停止本地设备Service和停止远程设备Service,使用方法与启动Service一样。一旦调用停止Service的方法,系统便会尽快销毁Service。

生命周期

根据调用方法的不同,其生命周期有以下两种路径:

  • 启动Service

    该Service在其他Ability调用startAbility()时创建,然后保持运行。其他Ability通过调用stopAbility()来停止Service,Service停止后,系统会将其销毁。

  • 连接Service

    该Service在其他Ability调用connectAbility()时创建,客户端可通过调用disconnectAbility()断开连接。多个客户端可以绑定到相同Service,而且当所有绑定全部取消后,系统即会销毁该Service。

    connectAbility()也可以连接通过startAbility()创建的Service。

*连接/停止 Service

启动和链接的差异

启动是无需数据传输的,链接是有数据传输的。

连接 Service 后,可以进行通信,需要连接后的 Service 执行任务之后返回数据,要用连接,就不能使用启动

Data Ability

使用Data模板的Ability(以下简称“Data”)有助于应用管理其自身和其他应用存储数据的访问,并提供与其他应用共享数据的方法。Data既可用于同设备不同应用的数据共享,也支持跨设备不同应用的数据共享。

数据的存放形式多样,可以是数据库,也可以是磁盘上的文件。Data对外提供对数据的增、删、改、查,以及打开文件等接口,这些接口的具体实现由开发者提供。

Intent

Intent是对象之间传递信息的载体。例如,当一个Ability需要启动另一个Ability时,或者一个AbilitySlice需要导航到另一个AbilitySlice时,可以通过Intent指定启动的目标同时携带相关数据。Intent的构成元素包括Operation与Parameters。

属性 子属性 描述
Operation Action 表示动作,通常使用系统预置Action,应用也可以自定义Action。例如IntentConstants.ACTION_HOME表示返回桌面动作。
Entity 表示类别,通常使用系统预置Entity,应用也可以自定义Entity。例如Intent.ENTITY_HOME表示在桌面显示图标。
Uri 表示Uri描述。如果在Intent中指定了Uri,则Intent将匹配指定的Uri信息,包括scheme, schemeSpecificPart, authority和path信息。
Flags 表示处理Intent的方式。例如Intent.FLAG_ABILITY_CONTINUATION标记在本地的一个Ability是否可以迁移到远端设备继续运行。
BundleName 表示包描述。如果在Intent中同时指定了BundleName和AbilityName,则Intent可以直接匹配到指定的Ability。
AbilityName 表示待启动的Ability名称。如果在Intent中同时指定了BundleName和AbilityName,则Intent可以直接匹配到指定的Ability。
DeviceId 表示运行指定Ability的设备ID。
Parameters - Parameters是一种支持自定义的数据结构,开发者可以通过Parameters传递某些请求所需的额外信息。

当Intent用于发起请求时,根据指定元素的不同,分为两种类型:

  • 如果同时指定了BundleName与AbilityName,则根据Ability的全称(例如“com.demoapp.FooAbility”)来直接启动应用。
  • 如果未同时指定BundleName和AbilityName,则根据Operation中的其他属性来启动应用。

说明

Intent设置属性时,必须先使用Operation来设置属性。如果需要新增或修改属性,必须在设置Operation后再执行操作。

公共事件和通知

*公共事件

CES(Common Event Service,公共事件服务):为应用程序提供订阅、发布、退订公共事件的能力,通过 ANS(Advanced Notification Service,通知增强服务)系统为应用程序提供发布通知的能力。

公共事件可分为

  • 系统公共事件
  • 自定义公共事件

通知

HarmonyOS提供了通知功能,即在一个应用的UI界面之外显示的消息,主要用来提醒用户有来自该应用中的信息。当应用向系统发出通知时,它将先以图标的形式显示在通知栏中,用户可以下拉通知栏查看通知的详细信息。常见的使用场景:

  • 显示接收到短消息、即时消息等。
  • 显示应用的推送消息,如广告、版本更新等。
  • 显示当前正在进行的事件,如播放音乐、导航、下载等。

NotificationSlot

NotificationSlot可以设置公共通知的震动,重要级别等,并通过调用NotificationHelper.addNotificationSlot()发布NotificationSlot对象。

一个应用可以创建一个或多个NotificationSlot,在发布通知时,通过绑定不同的NotificationSlot,实现不同用途。

  • 说明

NotificationSlot需要先通过NotificationHelper的addNotificationSlot(NotificationSlot)方法发布后,通知才能绑定使用;所有绑定该NotificationSlot的通知在发布后都具备相应的特性,对象在创建后,将无法更改这些设置,对于是否启动相应设置,用户有最终控制权。

不指定NotificationSlot时,当前通知会使用默认的NotificationSlot,默认的NotificationSlot优先级为LEVEL_DEFAULT。

*IntentAgent开发

IntentAgent封装了一个指定行为的Intent,可以通过triggerIntentAgent接口主动触发,也可以与通知绑定被动触发。具体的行为包括:启动Ability和发布公共事件。例如:收到通知后,在点击通知后跳转到一个新的Ability,不点击则不会触发。

*后台代理定时提醒开发

在应用开发时,可以调用后台代理提醒类ReminderRequest去创建定时提醒,包括倒计时、日历、闹钟三种提醒类型。使用后台代理提醒能力后,应用可以被冻结或退出,计时和弹出提醒的功能将被后台系统服务代理。

后台任务调度和管控

HarmonyOS将应用的资源使用生命周期划分为前台、后台和挂起三个阶段。

  • 前台:不受资源调度的约束
  • 后台:根据应用业务的具体任务情况进行资源使用管理
  • 挂起:会对应用的资源使用进行调度和控制约束,以保障其他体验类业务对资源的竞争使用。

后台任务类型

  1. 无后台业务。
  2. 短时任务。退出后有短时间需要完成的任务,例如数据压缩等。使用时 申请延迟进入挂起状态(Suspend)
  3. 长驻任务:例如后台下载,后台播放音乐等,进入常驻任务避免挂起。

短时任务

遵循如下规则:

  • 申请时机:允许应用在前台或在被挂起之间申请。默认退出再后台有 6~12秒运行时长
  • 超时(TimeOut)系统通过回调通知应用,应用需要 取消对应的延迟 或者 再次申请延迟挂起 。超过时间期限或不处理,将会被强制取消延迟挂起。
  • 取消时机:任务完成后应用应 主动取消延时申请
  • 配额机制:每个应用每天根据用户习惯会有一定的配额,根据用户的习惯动态调整。

长驻任务

长驻任务,可以通过使用长驻任务对应的后台模式保障业务在后台的运行,支撑应用在完成后台的业务。可以参考下一小节——后台模式分类。

后台模式分类

HarmonyOS提供了十种后台模式,供需要在后台做长驻任务的业务使用,具体的后台模式类型如下:

长驻任务后台模式 英文名 描述
数据传输 data-transfer 通过网络/对端设备进行数据下载、备份、分享、传输等业务
播音 audio-playback 音频输出业务
录音 audio-recording 音频输入业务
画中画 picture-in-picture 画中画、小窗口播放视频业务
音视频通话 voip 音视频电话,VoIP业务
导航/位置更新 location 定位、导航业务
蓝牙设备连接及传输 bluetooth-interaction 蓝牙扫描、连接、传输业务
WLAN设备连接及传输 wifi-interaction WLAN扫描、连接、传输业务
屏幕抓取 screen-fetch 录屏、截屏业务
多设备互联 multiDeviceConnection 多设备互联,分布式调度和迁移等业务

托管长驻任务

托管任务

托管任务是系统提供的一种后台代理机制。通过系统提供的代理API接口,用户可以把任务(如后台下载、定时提醒、后台非持续定位)交由系统托管。

类型

  1. 后台非持续性定位(non-sustained Location):如果应用未申请location常驻模式,且在后台依然尝试获取位置信息,此时应用行为被视为使用非持续定位能力,后台非持续定位限制每30分钟提供一次位置信息。应用不需要高频次定位时,建议优先使用非持续定位。
  2. 后台提醒代理(Reminder):后台提醒代理主要提供了一种机制,使开发者在应用开发时,可以调用这些接口去创建定时提醒,包括倒计时、日历、闹钟三种提醒类型。使用后台代理提醒能力后,应用可以被冻结或退出,计时和弹出提醒的功能将被后台系统服务代理。参考:Reminder接口使用说明
  3. 后台下载代理:系统提供DownloadSession接口实现下载任务代理功能,应用提交下载任务后,应用被退出,下载任务仍然可以继续执行,且支持下载任务断点续传。参考:DownloadSession接口使用说明

使用约束

  1. 后台下载代理,系统会根据用户场景和设备状态,对不同的下载任务进行相应的管控,避免影响功耗和性能。
  2. 后台非持续定位和后台提醒代理需要 申请对应的权限 。后台提醒需要申请 ohos.permission.PUBLISH_AGENT_REMINDER 权限,后台非持续定位需要申请 ohos.permission.LOCATION和ohos.permission.LOCATION_IN_BACKGROUND权限。
  3. 资源滥用会影响系统性能和功耗,托管任务类型要与应用类型匹配;匹配规则

FAQ

Frequently Asked Questions

  • 什么样的应用不受后台任务调度和管控的约束,不被挂起(Suspend)?

    原则上所有应用都会受后台任务调度和管控的约束,仅仅是约束的时机和状态不同而已。系统提供了选择设置的方式供用户从使用需求维度干预后台任务调度和管控,以华为手机举例,设置路径:手机管家->应用启动管理->选择手动管理->允许后台活动。

  • 应用后台任务调度和管控与那些因素有关?

    应用后台任务调度和管控以支撑用户使用体验为第一优先级,结合用户使用习惯、用户使用情景状态、设备模式状态、应用分类、应用资源占用统计等多个维度综合判断应用后台任务调度和管控的优先级。

  • 后台任务调度和管控机制的适用范围?

    后台任务调度和管控机制仅对HarmonyOS应用进行调度和管控。

线程管理

不同应用在各自独立的进程中运行。当应用以任何形式启动时,系统为其创建 进程,该进程将持续运行。当进程完成当前任务处于等待状态,且系统资源不足时,系统自动回收。

在启动应用时,系统会为该应用创建一个称为“主线程”的执行线程。该线程随着应用创建或消失,是应用的核心线程。UI界面的显示和更新等操作,都是在主线程上进行。主线程又称UI线程,默认情况下,所有的操作都是在主线程上执行。如果需要执行比较耗时的任务(如下载文件、查询数据库),可创建其他线程来处理。

TaskDispatcher

可以使用“TaskDispatcher”来分发不同的任务。TaskDispatcher是一个任务分发器,它是Ability分发任务的基本接口,隐藏任务所在线程的实现细节。为保证应用有更好的响应性,我们需要设计任务的优先级。在UI线程上运行的任务默认以高优先级运行,如果某个任务无需等待结果,则可以用低优先级。

优先级 详细描述
HIGH 最高任务优先级,比默认优先级、低优先级的任务有更高的几率得到执行。
DEFAULT 默认任务优先级, 比低优先级的任务有更高的几率得到执行。
LOW 低任务优先级,比高优先级、默认优先级的任务有更低的几率得到执行。

TaskDispatcher具有多种实现,每种实现对应不同的任务分发器。在分发任务时可以指定任务的优先级,由同一个任务分发器分发出的任务具有相同的优先级。

  • GlobalTaskDispatcher

    全局并发任务分发器,由Ability执行getGlobalTaskDispatcher()获取。适用于任务之间没有联系的情况。一个应用只有一个GlobalTaskDispatcher,它在程序结束时才被销毁。

    1
    TaskDispatcher globalTaskDispatcher = getGlobalTaskDispatcher(TaskPriority.DEFAULT);
  • ParallelTaskDispatcher

    并发任务分发器,由Ability执行createParallelTaskDispatcher()创建并返回。与GlobalTaskDispatcher不同的是,ParallelTaskDispatcher不具有全局唯一性,可以创建多个。开发者在创建或销毁dispatcher时,需要持有对应的对象引用 。

    1
    2
    String dispatcherName = "parallelTaskDispatcher";
    TaskDispatcher parallelTaskDispatcher = createParallelTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);
  • SerialTaskDispatcher

    串行任务分发器,由Ability执行createSerialTaskDispatcher()创建并返回。由该分发器分发的所有的任务都是按顺序执行,但是执行这些任务的线程并不是固定的。如果要执行并行任务,应使用ParallelTaskDispatcher或者GlobalTaskDispatcher,而不是创建多个SerialTaskDispatcher。如果任务之间没有依赖,应使用GlobalTaskDispatcher来实现。它的创建和销毁由开发者自己管理,开发者在使用期间需要持有该对象引用。

    1
    2
    String dispatcherName = "serialTaskDispatcher";
    TaskDispatcher serialTaskDispatcher = createSerialTaskDispatcher(dispatcherName, TaskPriority.DEFAULT);
  • SpecTaskDispatcher

    专有任务分发器,绑定到专有线程上的任务分发器。目前已有的专有线程为UI线程,通过UITaskDispatcher进行任务分发。

    UITaskDispatcher:绑定到应用主线程的专有任务分发器, 由Ability执行getUITaskDispatcher()创建并返回。 由该分发器分发的所有的任务都是在主线程上按顺序执行,它在应用程序结束时被销毁。

    1
    TaskDispatcher uiTaskDispatcher = getUITaskDispatcher();

*创建八种任务

*线程间通信开发

EventHandler是HarmonyOS用于处理线程间通信的一种机制,可以通过EventRunner创建新线程,将耗时的操作放到新线程上执行。这样既不阻塞原来的线程,任务又可以得到合理的处理。比如:主线程使用EventHandler创建子线程,子线程做耗时的下载图片操作,下载完成后,子线程通过EventHandler通知主线程,主线程再更新UI。

剪切板

SystemPasteboard提供系统剪贴板操作的相关接口,比如复制、粘贴、配置回调等。PasteData是剪贴板服务操作的数据对象,一个PasteData由若干个内容节点(PasteData.Record)和一个属性集合对象(PasteData.DataProperty)组成。Record是存放剪贴板数据内容信息的最小单位,每个Record都有其特定的MIME类型,如纯文本、HTML、URI、Intent。剪贴板数据的属性信息存在放PasteData.DataProperty中,包括标签、时间戳等。