- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
Page模板(以下简称“Page”)是FA唯一支持的模板,用于提供与用户交互的能力。一个Page可以由一个或多个AbilitySlice构成,AbilitySlice是指应用的单个页面及其控制逻辑的总和。
当一个Page由多个AbilitySlice共同构成时,这些AbilitySlice页面提供的业务能力应具有高度相关性。例如,新闻浏览功能可以通过一个Page来实现,其中包含了两个AbilitySlice:一个AbilitySlice用于展示新闻列表,另一个AbilitySlice用于展示新闻详情。Page和AbilitySlice的关系如图1所示。
图1 Page与AbilitySlice
相比于桌面场景,移动场景下应用之间的交互更为频繁。通常,单个应用专注于某个方面的能力开发,当它需要其他能力辅助时,会调用其他应用提供的能力。例如,外卖应用提供了联系商家的业务功能入口,当用户在使用该功能时,会跳转到通话应用的拨号页面。与此类似,HarmonyOS支持不同Page之间的跳转,并可以指定跳转到目标Page中某个具体的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"
]
}
]
...
}
]
...
}
...
}
系统管理或用户操作等行为均会引起Page实例在其生命周期的不同状态之间进行转换。Ability类提供的回调机制能够让Page及时感知外界变化,从而正确地应对状态变化(比如释放资源),这有助于提升应用的性能和稳健性。
Page生命周期的不同状态转换及其对应的回调,如图1所示。
图1 Page生命周期
@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作为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间导航时则由应用负责实例化。
当AbilitySlice处于前台且具有焦点时,其生命周期状态随着所属Page的生命周期状态的变化而变化。当一个Page拥有多个AbilitySlice时,例如:MyAbility下有FooAbilitySlice和BarAbilitySlice,当前FooAbilitySlice处于前台并获得焦点,并即将导航到BarAbilitySlice,在此期间的生命周期状态变化顺序为:
FooAbilitySlice从ACTIVE状态变为INACTIVE状态。
BarAbilitySlice则从INITIAL状态首先变为INACTIVE状态,然后变为ACTIVE状态(假定此前BarAbilitySlice未曾启动)。
FooAbilitySlice从INACTIVE状态变为BACKGROUND状态。
对应两个slice的生命周期方法回调顺序为:
FooAbilitySlice.onInactive() --> BarAbilitySlice.onStart() --> BarAbilitySlice.onActive() --> FooAbilitySlice.onBackground()
在整个流程中,MyAbility始终处于ACTIVE状态。但是,当Page被系统销毁时,其所有已实例化的AbilitySlice将联动销毁,而不仅是处于前台的AbilitySlice。
当发起导航的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()进行设置。
@Override
protected void onStart(Intent intent) {
...
Button button = ...;
button.setClickedListener(listener -> presentForResult(new TargetSlice(), new Intent(), 0));
...
}
@Override
protected void onResult(int requestCode, Intent resultIntent) {
if (requestCode == 0) {
// Process resultIntent here.
}
}
系统为每个Page维护了一个AbilitySlice实例的栈,每个进入前台的AbilitySlice实例均会入栈。当开发者在调用present()或presentForResult()时指定的AbilitySlice实例已经在栈中存在时,则栈中位于此实例之上的AbilitySlice均会出栈并终止其生命周期。前面的示例代码中,导航时指定的AbilitySlice实例均是新建的,即便重复执行此代码(此时作为导航目标的这些实例是同一个类),也不会导致任何AbilitySlice出栈。
AbilitySlice作为Page的内部单元,以Action的形式对外暴露,因此可以通过配置Intent的Action导航到目标AbilitySlice。Page间的导航可以使用startAbility()或startAbilityForResult()方法,获得返回结果的回调为onAbilityResult()。在Ability中调用setResult()可以设置返回结果。详细用法可参考根据Operation的其他属性启动应用中的示例。
跨设备迁移(下文简称“迁移”)支持将Page在同一用户的不同设备间迁移,以便支持用户无缝切换的诉求。以Page从设备A迁移到设备B为例,迁移动作主要步骤如下:
说明
一个应用可能包含多个Page,仅需要在支持迁移的Page中通过以下方法实现IAbilityContinuation接口。同时,此Page所包含的所有AbilitySlice也需要实现此接口。
实现IAbilityContinuation的Page可以在其生命周期内,调用continueAbility()或continueAbilityReversibly()请求迁移。两者的区别是,通过后者发起的迁移此后可以进行回迁。
try {
continueAbility();
} catch (IllegalStateException e) {
// Maybe another continuation in progress.
...
}
以Page从设备A迁移到设备B为例,详细的流程如下:
使用continueAbilityReversibly()请求迁移并完成后,源侧设备上已迁移的Page可以发起回迁,以便使用户活动重新回到此设备。
try {
reverseContinueAbility();
} catch (IllegalStateException e) {
// Maybe another continuation in progress.
...
}
以Page从设备A迁移到设备B后并请求回迁为例,详细的流程如下:
我需要一些说明。我可以直接写入 /dev/port 以直接访问并行端口并且它工作正常(我可以打开插入端口连接器的 LED)。但是,我想我可以用 /dev/mem 做同样的事情? (http://tld
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我使用 Visual C++ 和 Win32 API 学习了 Windows 编程。如今,似乎大多数应用程序都是使用 C# 在 .NET 中开发的。我知道大多数时候 native 代码和托管代码之间没
请耐心等待。我正在制作一个 java 控制台,类似于此处找到的 DragonConsole https://code.google.com/p/dragonconsole/ 。一切都按计划进行,但我想
关闭。这个问题需要更多 focused .它目前不接受答案。 想要改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭5年前。 Improve this que
Django 的开发服务器表现得很奇怪。访问它的浏览器在加载时卡住,任何退出它的尝试都不起作用。当我点击 control c看似相当,但实际上仍在运行。让它退出的唯一方法是重新启动我的电脑,这很令人沮
我正在使用 Flash Develop,并且创建了一个 ActionScript 3.0 项目。它启动并读取一个 xml 文件,其中包含图像的 url。我已将 url 保留在与 swf 相同的文件夹中
是否可以根据其 website 上提供的规范开发 AUTOSAR BSW 堆栈(例如用于 CAN 通信)?不购买任何昂贵的供应商工具?可以遵循哪些步骤?我被要求探索这种可能性。 最佳答案 是和否。工具
有人知道如何用音频文件的内容覆盖 iPhone 麦克风吗? 想象一个场景,您正在通话,并且想要播放一些简短的音频让其他人听到。 因此,有必要将麦克风(硬件)置于保持状态,并使用委托(delegate)
我遇到了这个问题,我的应用程序出现 EXC_BAD_ACCESS 错误并卡住/停止。我使用模拟器的“向左旋转”和“向右旋转”选项来模拟方向变化行为。导致此错误的可能原因有哪些?由于我没有获得有关错误的
我有超过 1 台 Mac,我想在所有这些 Mac 上进行开发。我知道我需要在每台机器上同步我的手机,但这是我遇到的最小的问题。看起来我无法在手机上运行应用程序,除了在其中之一上开发的应用程序。 是否有
在手机上测试时,我的应用程序在特定点崩溃。控制台显示此消息 Tue Jan 27 15:47:14 unknown SpringBoard[22] : Application com.myprof.
我有一个案例,我从服务器获取信息。我的应用程序有一个选项卡栏和导航按钮。我希望应用程序显示进度指示器并禁用所有其他控件,以便用户在从服务器提取数据时无法跳转。我怎样才能实现这个目标? 我想到的一种方法
有时,当我尝试“构建”/编译下载的源代码时,我会收到以下警告: ld: warning: directory '/Volumes/Skiiing2/CD/ViewBased/Unknown Path/
我无法在 Apple 文档中找到关于开发和分发配置之间差异的明确解释。我目前正在使用开发配置在我的 iPhone 上进行开发和测试。我打算将该应用程序分发到我的 Beta 测试中,我想知道: 我需要使
我在使用 SharePoint 时遇到的最大挑战之一是它不能很好地适应典型的项目环境,其中至少包含开发和生产环境。我遇到的最多的问题是内容和列表是如此紧密地耦合在一起,以至于如果不在生产环境中执行内容
我失败了fist step让 Eclipse(对我来说是全新的)为 ARM 开发做好准备。 我在 Windows 10 中安装了 Eclipse。我想我应该安装 xpm,但我不知道在哪里输入此命令:
首先,我告诉你-我是编码新手 我正在使用vs代码来学习c++,它不会产生像dev c++或codeblocks这样的调试器。我看了一些视频,其中我们必须编辑json文件,这对于初学者来说非常复杂。有人
我失败了fist step让 Eclipse(对我来说是全新的)为 ARM 开发做好准备。 我在 Windows 10 中安装了 Eclipse。我想我应该安装 xpm,但我不知道在哪里输入此命令:
我开发了一个 Ionic 应用程序(iOS 和 Android 的混合)。我有 Xcode 8.3.3 并购买了一年的 Apple Developer Program 订阅。 我不想测试我的应用并将其
我是一名优秀的程序员,十分优秀!