OpenHarmony应用开发-FA模型开发指导
版本:v3.2 Beta5
进程模型
OpenHarmony的进程模型如下图所示:
- 应用中(同一包名)的所有PageAbility、ServiceAbility、DataAbility、FormAbility运行在同一个独立进程中,即图中绿色部分的“Main Process”。
- WebView拥有独立的渲染进程,即图中黄色部分的“Render Process”。
图1进程模型示意图
基于OpenHarmony的进程模型,应用间存在多个进程的情况,因此系统提供了如下两种进程间通信机制:
- 公共事件机制:多用于一对多的通信场景,公共事件发布者可能存在多个订阅者同时接收事件。
- 后台服务机制:当前主要通过ServiceAbility的能力实现。
公共事件
请参见Stage模型的"公共事件"。
后台服务
请参见Stage模型的"后台服务"。
线程模型
FA模型下的线程主要有如下三类:
- 主线程 负责管理其他线程
- Ability线程
○ 每个Ability一个线程
○ 输入事件分发
○ UI绘制
○ 应用代码回调(事件处理,生命周期)
○ 接收Worker发送的消息
- Worker线程 执行耗时操作
基于OpenHarmony的线程模型,不同的业务功能运行在不同的线程上,业务功能的交互就需要线程间通信。线程间通信目前主要有Emitter和Worker两种方式,其中Emitter主要适用于线程间的事件同步, Worker主要用于新开一个线程执行耗时任务。
说明: FA模型每个ability都有一个独立的线程,Emiter可用于Ability线程内、Ability线程间、Ability线程与Worker线程的事件同步。
线程间通信
请参见Stage模型的"线程间通信"。
任务管理
请参见Stage模型的"任务管理"。
FA模型与Stage模型应用组件互通综述
API 8及以前的接口基于FA模型提供;从API 9开始,OpenHarmony主推Stage模型。FA模型与Stage模型是两套不同的应用模型,他们拥有各自的组件。FA模型提供三种应用组件,分别是PageAbility、ServiceAbility和DataAbility。Stage模型提供了两种应用组件,分别是UIAbility和ExtensionAbility。
由于FA模型与Stage模型不能在应用内混合开发(见下图),当一个设备(系统)内包含两种模型应用时(下图中"场景三"),可能涉及两种模型应用组件间的互通,本文将介绍相关互通指导。
图1 FA模型与Stage模型应用组件共存场景
FA模型与Stage模型应用组件互通场景及开发者关注点请参考下表。
表1 FA模型与Stage模型应用组件互通概览
互通场景 | 开发者关注点 |
只需要把want中的bundleName和abilityName替换成Stage模型UIAbility的bundleName和abilityName。 | |
只需要把want中的bundleName和abilityName替换成Stage模型ServiceExtensionAbility的bundleName和abilityName。 | |
无需做代码修改。但需了解DataShareHelper和DataAbilityHelper对外接口的兼容情况。 | |
只需要把want中的bundleName和abilityName替换成FA模型PageAbility的bundleName和abilityName。 | |
只需要把want中的bundleName和abilityName替换成FA模型ServiceAbility的bundleName和abilityName。 | |
Stage模型访问FA模型DataAbility | 不支持此种访问。 |
FA模型启动Stage模型UIAbility
本文介绍FA模型的三种应用组件如何启动Stage模型的UIAbility组件。
PageAbility启动UIAbility
在PageAbility中启动UIAbility和在PageAbility中启动PageAbility的方式完全相同。
import featureAbility from '@ohos.ability.featureAbility';
let parameter = {
"want": {
bundleName: "com.ohos.stage",
abilityName: "com.ohos.stage.MainAbility"
}
};
featureAbility.startAbility(parameter).then((code) => {
console.info('Ability verify code: ' + JSON.stringify(code));
}).catch((error) => {
console.error("Ability failed: " + JSON.stringify(error));
});
PageAbility访问UIAbility(startAbilityForResult)
startAbilityForResult和startAbility的区别是当UIAbility销毁的时候会返回执行结果。
在PageAbility中通过startAbilityForResult启动UIAbility和在PageAbility中通过startAbilityForResult启动PageAbility的方式完全相同。
import featureAbility from '@ohos.ability.featureAbility';
let parameter = {
"want": {
bundleName: "com.ohos.stage",
abilityName: "com.ohos.stage.MainAbility"
}
};
featureAbility.startAbilityForResult(parameter).then((result) => {
console.info('Ability verify result: ' + JSON.stringify(result));
}).catch((error) => {
console.error("Ability failed: " + JSON.stringify(error));
});
ServiceAbility/DataAbility启动UIAbility
在ServiceAbility/DataAbility中启动UIAbility和在ServiceAbility/DataAbility中启动PageAbility的方式完全相同。
import particleAbility from '@ohos.ability.particleAbility';
let parameter = {
"want": {
bundleName: "com.ohos.stage",
abilityName: "com.ohos.stage.MainAbility"
}
};
particleAbility.startAbility(parameter).then(() => {
console.info('Start Ability successfully.');
}).catch((error) => {
console.error("Ability failed: " + JSON.stringify(error));
});
FA模型绑定Stage模型ServiceExtensionAbility
本文介绍FA模型的三种应用组件如何绑定Stage模型的ServiceExtensionAbility组件。
PageAbility关联访问ServiceExtensionAbility
PageAbility关联访问ServiceExtensionAbility和PageAbility关联访问ServiceAbility的方式完全相同。
import featureAbility from '@ohos.ability.featureAbility';
let want = {
bundleName: "com.ohos.stage",
abilityName: "com.ohos.stage.ServiceExtensionAbility"
};
let faConnect = {
onConnect:function (elementName, proxy) {
console.info("Faconnection onConnect called.");
},
onDisconnect:function (elementName) {
console.info("Faconnection onDisconnect called.");
},
onFailed:function (code) {
console.info("Faconnection onFailed code is: " + code);
}
};
let connectionId = featureAbility.connectAbility(want, faConnect);
ServiceAbility/DataAbility关联访问ServiceExtensionAbility
ServiceAbility/DataAbility关联访问ServiceExtensionAbility和ServiceAbility/DataAbility关联访问ServiceAbility的方式完全相同。
import particleAbility from '@ohos.ability.particleAbility';
let want = {
bundleName: "com.ohos.stage",
abilityName: "com.ohos.stage.ServiceExtensionAbility"
};
let faConnect = {
onConnect:function (elementName, proxy) {
console.info("Faconnection onConnect called.");
},
onDisconnect:function (elementName) {
console.info("Faconnection onDisconnect called.");
},
onFailed:function (code) {
console.info("Faconnection onFailed code is: " + code);
}
};
let connectionId = particleAbility.connectAbility(want, faConnect);
FA模型访问Stage模型DataShareExtensionAbility
概述
无论FA模型还是Stage模型,数据读写功能都包含客户端和服务端两部分。
- FA模型中,客户端是由DataAbilityHelper提供对外接口,服务端是由DataAbility提供数据库的读写服务。
- Stage模型中,客户端是由DataShareHelper提供对外接口,服务端是由DataShareExtensionAbility提供数据库的读写服务。
服务端由FA模型升级到Stage模型后,会导致FA模型的客户端在API 9(含)之后的版本上无法访问服务端。
为了解决上述问题,OpenHarmony在框架侧提供了一个解决方案,让开发者平滑过渡到API 9(含)之后的版本。
基本原理
一种兼容方法是DataAbilityHelper根据传入的URI的前缀是DataAbility还是DataShare来决定是否调DataShareHelper的接口。但是这种方法需要开发者修改原客户端代码的URI,做不到无感知切换。
因此DataAbilityHelper不能仅依赖URI的前缀决定访问DataAbility还是DataShareExtensionAbility,OpenHarmony采用的方法是:
- 先按照传入的URI拉起DataAbility;如果拉起失败,再将传入的URI的前缀转换成DataShare再去尝试拉起DataShareExtensionAbility。
- 如果URI无对应的DataAbility和DataShareExtensionAbility,则拉起失败;反之,必定会拉起DataAbility或者DataShareExtensionAbility。
约束与限制
- 由DataAbility切换到DataShareExtensionAbility时,只能修改URI的前缀,不能修改URI的其他部分。
- DataShareHelper并没有实现原DataAbilityHelper对外API接口的所有功能,因此有部分接口是无法兼容的,具体如表1所示。
表1 FA模型访问stage模型DataShareExtensionAbility接口支持情况
接口 | DataAbilityHelper是否提供 | DataShareHelper是否提供 | 是否兼容 |
on | 是 | 是 | 是 |
off | 是 | 是 | 是 |
notifyChange | 是 | 是 | 是 |
insert | 是 | 是 | 是 |
delete | 是 | 是 | 是 |
query | 是 | 是 | 是 |
update | 是 | 是 | 是 |
batchInsert | 是 | 是 | 是 |
getType | 是 | 否 | 否 |
getFileTypes | 是 | 否 | 否 |
normalizeUri | 是 | 是 | 是 |
denormalizeUri | 是 | 是 | 是 |
openFile | 是 | 否 | 否 |
call | 是 | 否 | 否 |
executeBatch | 是 | 否 | 否 |
Stage模型启动FA模型PageAbility
本小节介绍Stage模型的两种应用组件如何启动FA模型的PageAbility组件。
UIAbility启动PageAbility
UIAbility启动PageAbility和UIAbility启动UIAbility的方式完全相同。
import UIAbility from '@ohos.app.ability.UIAbility'
export default class MainAbility extends UIAbility {
onCreate(want, launchParam) {
console.info("MainAbility onCreate")
}
onDestroy() {
console.info("MainAbility onDestroy")
}
onWindowStageCreate(windowStage) {
console.info("MainAbility onWindowStageCreate")
windowStage.loadContent('pages/Index', (err, data) => {
// ...
});
let want = {
bundleName: "com.ohos.fa",
abilityName: "MainAbility",
};
this.context.startAbility(want).then(() => {
console.info('Start Ability successfully.');
}).catch((error) => {
console.error("Ability failed: " + JSON.stringify(error));
});
}
onWindowStageDestroy() {
console.info("MainAbility onWindowStageDestroy")
}
onForeground() {
console.info("MainAbility onForeground")
}
onBackground() {
console.info("MainAbility onBackground")
}
}
UIAbility访问PageAbility(startAbilityForResult)
startAbilityForResult和startAbility的区别是当PageAbility销毁的时候会返回执行结果。
UIAbility通过startAbilityForResult启动PageABility和UIAbility通过startAbilityForResult启动UIAbility的代码一样,没有任何区别。
import UIAbility from '@ohos.app.ability.UIAbility'
export default class MainAbility extends UIAbility {
onCreate(want, launchParam) {
console.info("MainAbility onCreate")
}
onDestroy() {
console.info("MainAbility onDestroy")
}
onWindowStageCreate(windowStage) {
console.info("MainAbility onWindowStageCreate")
windowStage.loadContent('pages/Index', (err, data) => {
// ...
});
let want = {
bundleName: "com.ohos.fa",
abilityName: "MainAbility",
};
this.context.startAbilityForResult(want).then((result) => {
console.info('Ability verify result: ' + JSON.stringify(result));
}).catch((error) => {
console.error("Ability failed: " + JSON.stringify(error));
});
}
onWindowStageDestroy() {
console.info("MainAbility onWindowStageDestroy")
}
onForeground() {
console.info("MainAbility onForeground")
}
onBackground() {
console.info("MainAbility onBackground")
}
}
ExtensionAbility启动PageAbility
下面以ServiceExtensionAbility为例来说明ExtensionAbility启动PageAbility。ServiceExtensionAbility启动PageAbility和ServiceExtensionAbility启动UIAbility的方式完全相同。
import Extension from '@ohos.app.ability.ServiceExtensionAbility'
export default class ServiceExtension extends Extension {
onCreate(want) {
console.info("ServiceExtension onCreate")
}
onDestroy() {
console.info("ServiceExtension onDestroy")
}
onRequest(want, startId) {
console.info("ServiceExtension onRequest")
let wantFA = {
bundleName: "com.ohos.fa",
abilityName: "MainAbility",
};
this.context.startAbility(wantFA).then(() => {
console.info('Start Ability successfully.');
}).catch((error) => {
console.error("Ability failed: " + JSON.stringify(error));
});
}
}
Stage模型绑定FA模型ServiceAbility
本小节介绍Stage模型的两种应用组件如何绑定FA模型ServiceAbility组件。
UIAbility关联访问ServiceAbility
UIAbility关联访问ServiceAbility和UIAbility关联访问ServiceExtensionAbility的方式完全相同。
import UIAbility from '@ohos.app.ability.UIAbility';
export default class MainAbility extends UIAbility {
onCreate(want, launchParam) {
console.info("MainAbility onCreate");
}
onDestroy() {
console.info("MainAbility onDestroy")
}
onWindowStageCreate(windowStage) {
console.info("MainAbility onWindowStageCreate")
let want = {
bundleName: "com.ohos.fa",
abilityName: "ServiceAbility",
};
let options = {
onConnect:function (elementName, proxy) {
console.info("onConnect called.");
},
onDisconnect:function (elementName) {
console.info("onDisconnect called.");
},
onFailed:function (code) {
console.info("onFailed code is: " + code);
}
};
let connectionId = this.context.connectServiceExtensionAbility(want, options);
}
onWindowStageDestroy() {
console.info("MainAbility onWindowStageDestroy")
}
onForeground() {
console.info("MainAbility onForeground")
}
onBackground() {
console.info("MainAbility onBackground")
}
}
ExtensionAbility关联访问ServiceAbility
下面以ServiceExtensionAbility为例来说明ExtensionAbility关联访问ServiceAbility。ServiceExtensionAbility关联访问ServiceAbility和ServiceExtensionAbility关联访问ServiceExtensionAbility的方式完全相同。
import Extension from '@ohos.app.ability.ServiceExtensionAbility'
export default class ServiceExtension extends Extension {
onCreate(want) {
console.info("ServiceExtension onCreate")
}
onDestroy() {
console.info("ServiceExtension onDestroy")
}
onRequest(want, startId) {
console.info("ServiceExtension onRequest")
let wantFA = {
bundleName: "com.ohos.fa",
abilityName: "ServiceAbility",
};
let options = {
onConnect:function (elementName, proxy) {
console.info("onConnect called.");
},
onDisconnect:function (elementName) {
console.info("onDisconnect called.");
},
onFailed:function (code) {
console.info("onFailed code is: " + code);
}
};
let connectionId = this.context.connectServiceExtensionAbility(wantFA, options);
}
}