HarmonyOS的软件包很有意思,叫做 APP Pack,它和Android的APK不同,因为分布式系统的缘故,它的软件包是个整体的概念,包含多个独立HAP(这个才相当于APK)。
而HAP和APK一样,都是由代码,资源,第三方库,应用配置文件组成的模块包。
HAP有两种模块类型,分别是entry,feature。前者是主入口模块。后者是单独的业务模块。
相当于Android中的四大组件(Activity,Service,ContentProvider,BroadcastReceiver)。
Ability分为两种类型:FA(Feature Ability)和PA(particle Abiltiy)。
Ability又拥有三种模板:
Page Ability
是FA唯一支持的模板,提供用户交互能力。
Service Ability
PA支持的模板,提供后台运行任务的能力。
Data Ability
PA支持的模板,提供统一的数据访问抽象。
在配置文件(config.json)中注册 Ability 时,可以通过配置 Ability 元素中的“type”属性来
指定 Ability 模板类型,示例如下:
{
"module": {
...
"abilities": [
{
...
"type": "page"
...
}
]
...
}
Page Ability是个整体概念,不单独指的是一个页面,而是可能包含多个页面,Page 是模块的概念。每个页面是AbilitySlice实例表示,指的是应用的单个页面及其控制逻辑的总和。
所以Page Ability包含于AbilitySlice。这两者之间是有高度相关性,简单来说,就是同个模块的不同界面。例如商城模块,包含商品详情界面,商品列表界面。不能商城模块里,放一个用户权益界面。
Page模块不是一个简单概念,而是有操作实体的模块。因为它不像Android中简单的通过文件夹命名,包名区分模块,整个应用的跳转是统一路由维护。所以跳转到单独界面时,Page模块会维护一个路由,来维护跳转规则。
Page模块的默认展示页面AbilitySlice,通过setMainRoute() 来设置。
AbilitySlice的暴露对外的路由规则,用于其他Page模块跳转进入,通过AddActionroute() 来设置。
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());
}
}
addActionRoute()方法中使用的动作命名,需要在应用配置文件(config.json)中注册:
{
"module": {
"abilities": [
{
"skills":[
{
"actions":[
"action.pay",
"action.scan"
]
}
]
...
}
]
...
}
...
}
Page 生命周期:
onStart()
首次创建,只会触发一次。
onActive()
在前台展示,应用与用户交互的状态。
onInactive()
当 Page 失去焦点时
onBackground()
当Page 不再对用户可见,在后台
onForeground()
当重新回到前台时
onStop()
系统将要销毁 Page 时
当系统首次创建 Page 实例时,触发 onStart()回调。对于一个 Page 实例,该回调在其生命周期过程
中仅触发一次,Page 在该逻辑后将进入 INACTIVE 状态。开发者必须重写该方法,并在此配
置默认展示的 AbilitySlice。
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(FooSlice.class.getName());
}
AbilitySlice 作为 Page 的组成单元,其生命周期是依托于其所属 Page 生命周期的。
由于 AbilitySlice 承载具
体的页面,必须重写 AbilitySlice 的 onStart()回调,并在此方法中通过 setUIContent()
方法设置页面,如下所示:
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
setUIContent(ResourceTable.Layout_main_layout);
}
通过present()/presentForResult() 方法实现AbilitySlice间导航
@Override
protected void onStart(Intent intent) {
...
Button button = ...;
button.setClickedListener(listener -> present(new TargetSlice(), new Intent()));
...
}
int requestCode = positiveInteger; // Any positive integer.
@Override
protected void onStart(Intent intent) {
...
Button button = ...;
button.setClickedListener(
listener -> presentForResult(new TargetSlice(), new Intent(), positiveInteger));
...
}
@Override
protected void onResult(int requestCode, Intent resultIntent) {
if (requestCode == positiveInteger) {
// Process resultIntent here.
}
}
构造Operation对象,通过startAbility()/startAbilityForResult()实现不同Page间导航
请求方
在Ability中构造Intent以及包含Action的Operation对象,并调用startAbilityForResult()方法发起请求。然后重写onAbilityResult()回调方法,对请求结果进行处理。
private void queryWeather() {
Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withAction(Intent.ACTION_QUERY_WEATHER)
.build();
intent.setOperation(operation);
startAbilityForResult(intent, REQ_CODE_QUERY_WEATHER);
}
@Override
protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
switch (requestCode) {
case REQ_CODE_QUERY_WEATHER:
// Do something with result.
...
return;
default:
...
}
}
处理方
作为处理请求的对象,首先需要在配置文件中声明对外提供的能力,以便系统据此找到自身并作为候选的请求处理者
{
"module": {
...
"abilities": [
{
...
"skills":[
{
"actions":[
"ability.intent.QUERY_WEATHER"
]
}
]
...
}
]
...
}
...
}
在Ability中配置路由以便支持以此action导航到对应的AbilitySlice。
@Override
protected void onStart(Intent intent) {
...
addActionRoute(Intent.ACTION_QUERY_WEATHER, DemoSlice.class.getName());
...
}
在Ability中处理请求,并调用setResult()方法暂存返回结果。
@Override
protected void onActive() {
...
Intent resultIntent = new Intent();
setResult(0, resultIntent); //0为当前Ability销毁后返回的resultCode。
...
}