第二节·Ability——Page Ability

第二节·Ability——Page Ability

Ability(总述)

FA

FA(Feature Ability),FA支持Page Ability:Page模板是FA唯一支持的模板,用于提供与用户交互的能力。

Page Ability可以理解为前端页面

PA

PA(Particle Ability),PA支持Service Ability和Data Ability:Service模板用于提供后台运行任务的能力;Data模板用于对外部提供统一的数据访问抽象。

Service Ability可以理解为应用的后台进程

Data Ability可以理解为操纵数据库

Particle Ability可以理解为后端程序


配置文件(config.json)中注册Ability时,可以通过配置Ability元素中的“type”属性来指定Ability模板类型,示例如下。

其中,“type”的取值可以为“page”、“service”或“data”,分别代表Page模板、Service模板、Data模板。为了便于表述,后文中我们将基于Page模板、Service模板、Data模板实现的Ability分别简称为Page、Service、Data。

{
    "module": {
        ...
        "abilities": [
            {
                ...
                "type": "page"
                ...
            }
        ]
        ...
    }
    ...
}

Page Ability

Page与AbilitySlice

当一个Page由多个AbilitySlice共同构成时,这些AbilitySlice页面提供的业务能力应具有高度相关性。例如,新闻浏览功能可以通过一个Page来实现,其中包含了两个AbilitySlice:一个AbilitySlice用于展示新闻列表,另一个AbilitySlice用于展示新闻详情。Page和AbilitySlice的关系如图所示。

​ Page与AbilitySlice
img

相比于桌面场景,移动场景下应用之间的交互更为频繁。通常,单个应用专注于某个方面的能力开发,当它需要其他能力辅助时,会调用其他应用提供的能力。例如,外卖应用提供了联系商家的业务功能入口,当用户在使用该功能时,会跳转到通话应用的拨号页面。与此类似,HarmonyOS支持不同Page之间的跳转,并可以指定跳转到目标Page中某个具体的AbilitySlice。

AbilitySlice路由配置

虽然一个Page可以包含多个AbilitySlice,但是Page进入前台时界面默认只展示一个AbilitySlice。默认展示的AbilitySlice是通过setMainRoute()方法来指定的。如果需要更改默认展示的AbilitySlice,可以通过addActionRoute()方法为此AbilitySlice配置一条路由规则。此时,当其他Page实例期望导航到此AbilitySlice时,可以在Intent中指定Action,详见不同Page间导航

setMainRoute()方法与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"
                        ]
                    }
                ]
                ...
            }
        ]
        ...
    }
    ...
}

Intent(略讲)

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

属性子属性描述
OperationAction表示动作,通常使用系统预置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后再执行操作。

后面的课程中还会详细讲解


Page Ability生命周期

系统管理或用户操作等行为均会引起Page实例在其生命周期的不同状态之间进行转换。Ability类提供的回调机制能够让Page及时感知外界变化,从而正确地应对状态变化(比如释放资源),这有助于提升应用的性能和稳健性。

Page生命周期回调

Page生命周期的不同状态转换及其对应的回调,如图所示。

图: Page生命周期
点击放大

说明

INACTIVE状态是一种短暂存在的状态,可理解为“激活中”。

  • onStart()

    当系统首次创建Page实例时,触发该回调。对于一个Page实例,该回调在其生命周期过程中仅触发一次,Page在该逻辑后将进入INACTIVE状态。开发者必须重写该方法,并在此配置默认展示的AbilitySlice。

        @Override
        public void onStart(Intent intent) {
            super.onStart(intent);
            super.setMainRoute(FooSlice.class.getName());
        }
    
  • onActive()

    Page会在进入INACTIVE状态后来到前台,然后系统调用此回调。Page在此之后进入ACTIVE状态,该状态是应用与用户交互的状态。Page将保持在此状态,除非某类事件发生导致Page失去焦点,比如用户点击返回键或导航到其他Page。当此类事件发生时,会触发Page回到INACTIVE状态,系统将调用onInactive()回调。此后,Page可能重新回到ACTIVE状态,系统将再次调用onActive()回调。因此,开发者通常需要成对实现onActive()和onInactive(),并在onActive()中获取在onInactive()中被释放的资源。

  • onInactive()

    当Page失去焦点时,系统将调用此回调,此后Page进入INACTIVE状态。开发者可以在此回调中实现Page失去焦点时应表现的恰当行为。

  • onBackground()

    如果Page不再对用户可见,系统将调用此回调通知开发者用户进行相应的资源释放,此后Page进入BACKGROUND状态。开发者应该在此回调中释放Page不可见时无用的资源,或在此回调中执行较为耗时的状态保存操作。

  • onForeground()

    处于BACKGROUND状态的Page仍然驻留在内存中,当重新回到前台时(比如用户重新导航到此Page),系统将先调用onForeground()回调通知开发者,而后Page的生命周期状态回到INACTIVE状态。开发者应当在此回调中重新申请在onBackground()中释放的资源,最后Page的生命周期状态进一步回到ACTIVE状态,系统将通过onActive()回调通知开发者用户。

  • onStop()

    系统将要销毁Page时,将会触发此回调函数,通知用户进行系统资源的释放。销毁Page的可能原因包括以下几个方面:

    • 用户通过系统管理能力关闭指定Page,例如使用任务管理器关闭Page。
    • 用户行为触发Page的terminateAbility()方法调用,例如使用应用的退出功能。
    • 配置变更导致系统暂时销毁Page并重建。
    • 系统出于资源管理目的,自动触发对处于BACKGROUND状态Page的销毁。
AbilitySlice生命周期

AbilitySlice作为Page的组成单元,其生命周期是依托于其所属Page生命周期的。AbilitySlice和Page具有相同的生命周期状态和同名的回调,当Page生命周期发生变化时,它的AbilitySlice也会发生相同的生命周期变化。此外,AbilitySlice还具有独立于Page的生命周期变化,这发生在同一Page中的AbilitySlice之间导航时,此时Page的生命周期状态不会改变。

AbilitySlice生命周期回调与Page的相应回调类似,因此不再赘述。由于AbilitySlice承载具体的页面,开发者必须重写AbilitySlice的onStart()回调,并在此方法中通过setUIContent()方法设置页面,如下所示:

    @Override
    protected void onStart(Intent intent) {
        super.onStart(intent);

        setUIContent(ResourceTable.Layout_main_layout);
    }

AbilitySlice实例创建和管理通常由应用负责,系统仅在特定情况下会创建AbilitySlice实例。例如,通过导航启动某个AbilitySlice时,是由系统负责实例化;但是在同一个Page中不同的AbilitySlice间导航时则由应用负责实例化。

Page与AbilitySlice生命周期关联

当AbilitySlice处于前台且具有焦点时,其生命周期状态随着所属Page的生命周期状态的变化而变化。当一个Page拥有多个AbilitySlice时,例如:MyAbility下有FooAbilitySlice和BarAbilitySlice,当前FooAbilitySlice处于前台并获得焦点,并即将导航到BarAbilitySlice,在此期间的生命周期状态变化顺序为:

  1. FooAbilitySlice从ACTIVE状态变为INACTIVE状态。
  2. BarAbilitySlice则从INITIAL状态首先变为INACTIVE状态,然后变为ACTIVE状态(假定此前BarAbilitySlice未曾启动)。
  3. FooAbilitySlice从INACTIVE状态变为BACKGROUND状态。

对应两个slice的生命周期方法回调顺序为:

FooAbilitySlice.onInactive() --> BarAbilitySlice.onStart() --> BarAbilitySlice.onActive() --> FooAbilitySlice.onBackground()

在整个流程中,MyAbility始终处于ACTIVE状态。但是,当Page被系统销毁时,其所有已实例化的AbilitySlice将联动销毁,而不仅是处于前台的AbilitySlice。


不同页面间导航
同一Page内导航

当发起导航的AbilitySlice和导航目标的AbilitySlice处于同一个Page时,您可以通过present()方法实现导航。如下代码片段展示通过点击按钮导航到其他AbilitySlice的方法:

@Override
protected void onStart(Intent intent) {

    ...
    Button button = ...;
    button.setClickedListener(listener -> present(new TargetSlice(), new Intent()));
    ...

}

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

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.
    }
}

系统为每个Page维护了一个AbilitySlice实例的栈,每个进入前台的AbilitySlice实例均会入栈。当开发者在调用present()或presentForResult()时指定的AbilitySlice实例已经在栈中存在时,则栈中位于此实例之上的AbilitySlice均会出栈并终止其生命周期。前面的示例代码中,导航时指定的AbilitySlice实例均是新建的,即便重复执行此代码(此时作为导航目标的这些实例是同一个类),也不会导致任何AbilitySlice出栈。

不同Page间导航

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


下节内容

学习完以上基础知识,我们来实际项目里进行实操

在Java UI框架中,提供了两种编写布局的方式:在XML中声明UI布局和在代码中创建布局。这两种方式创建出的布局没有本质差别,都是我们需要熟悉方式,所以我们将通过XML的方式布局第一张页面,然后再通过代码的方式布局第二张页面。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值