一个典型的HarmonyOS应用应该有与用户交互的界面,完成应用功能的业务逻辑
和需要处理的业务数据
。简单来说就是用户通过应用看到什么,通过应用能做什么以及对什么东西做。当然,对于一个复杂应用,不会只有一个可视化页面,会包含承载很多功能的显示处理模块,这些功能模块需要进行跳转切换。
Ability是HarmonyOS应用程序的重要组成部分,分为FA
( Feature Ability)和PA
( Particle Ability)两种类型:
Page Ability
: Page模板是FA唯一支持的模板,用于提供与用户交互的能力。Service Ability
和Data Ability
: Service模板用于提供后台运行任务的能力;Data模板用于对外部提供统一的数据访问抽象。FA需要提供ul用于与用户进行交互,HarmonyOs提供了Java Ul和JS uI两种uI框架:
应用开发更加灵活
;应用开发更加简单
。针对轻量级智能穿戴( Lite Wearable ),现阶段只使用JS语言进行应用开发。
Ability是应用所具备能力的抽象,也是应用程序的重要组成部分。一个应用可以具备多种能力(即可以包含多个Ability ) ,HarmonyOS支持应用以Ability为单位进行部署。Ability可以分为FA( Feature Ability)和PA( Particle Ability)两种类型,每种类型为开发者提供了不同的模板,以便实现不同的业务功能。
AbilitySlice
是指应用的单个页面及其控制逻辑的总和
。新闻列表
,另一个AbilitySlice用于展示新闻详情
。setMainRoute()
方法来指定的。如果需要更改默认展示的AbilitySlice,可以通过addActionRoute()
方法为此AbilitySlice配置一条路由规则。此时,当其他Page实例期望导航到此AbilitySlice时,可以在Intent中指定Action。public class MyAbility extends Ability {
@Override
public void onStart(Intent intent){
super.onStart(intent);
setMainRoute(MainSlice.class.getName());
addActionRoute("action.paybyAlipay",PayAlipaySlice.class.getName());
addActionRoute("action.paybyWechat",PayWechatSlice.class.getName());
}
}
. addActionRoute()方法中使用的动作命名,需要在应用配置文件( config.json )中注册
{
"module": {
"abilities": [
{
"skills":[
{
"actions":[
"action.paybyAlipay",
"action.paybyWechat"
]
}
]
………
}
]
..
}...
}
lntent intent = new Intent();
Operation operation = new lntent.OperationBuilder().withAction("action.paybyAlipay").build();
intent.setOperation(operation);
startAbility (intent);
系统管理
或用户操作
等行为均会引起Page实例在其生命周期的不同状态之间进行转换。·当系统首次创建Paqe实例时,触发该回调。对于一个Page实例,该回调在其生命周期过程中仅触发一次
,Page在该逻辑后将进入INACTIVE状态。开发者必须重写该方法
,并在此配置默认展示的AbilitySlice。
@Override
public void onStart(Intent intent){super.onStart(intent);
super.setMainRoute(FooSlice.class.getName());}
用户点击返回键
或导航到其他Page
。当此类事件发生时,会触发Page回到INACTIVE状态,系统将调用onInactive()回调。BACKGROUND
状态的Page仍然驻留在内存中,当重新回到前台时(比如用户重新导航到此Page),系统将先调用onForeground()回调通知开发者,而后Page的生命周期状态回到INACTIVE状态。开发者应当在此回调中重新申请在onBackground()中释放的资源,最后Page的生命周期状态进一步回到ACTIVE状态,系统将通过onActive()回调通知开发者用户。系统管理能力
关闭指定Page,例如使用任务管理器关闭Pageo用户行为
触发Page的terminateAbility()方法调用,例如使用应用的退出功能。配置变更
导致系统暂时销毁Page并重建。资源管理目的
,自动触发对处于BACKGROUND状态Page的销毁。重写AbilitySlice的onStart()
回调,并在此方法中通过setUlContent()
方法设置页面。由应用负责实例化
@Override
protected void onStart(Intent intent){
super.onStart(intent);
setUlContent(ResourceTable.Layout_main_layout);
}
AbilitySlice实例栈
·当发起导航的AbilitySlice和导航目标的AbilitySlice处于同一个Page时,您可以通过present()
方法实现导航。
@Override
protected void onStart(Intent intent){
Button button = ...;
button.setClickedListener(listener -> present(new TargetSlice(), newlntent()));
}
AbilitySlice间数据传递
presentForResult()
实现导航。用户从导航目标AbilitySlice返回时,系统将回调onResult()
来接收和处理返回结果,开发者需要重写该方法。返回结果由导航目AbilitySlice在其生命周期内通过setResult()进行设置。源AbilitySlice
@Override
protected void onStart(Intent intent){
..
Button button = ..;
button.setClickedListener(listener -> presentForResult(new TargetSlice(), new Intent(),0));
..
}
@Override
protected void onResult(int requestCode,Intent resultlntent) {
if (requestCode == 0) {
//Process resultlntent here.
}
}
不同Page中的AbilitySlice相互不可见,因此无法通过present()或presentForResult()方法直接导航到其他Page的AbilitySlice。AbilitySlice作为Page的内部单元,以action的形式对外暴露,因此可以通过配置Intent的Action导航到目标AbilitySlice。
Page间的导航可以使用startAbility()
或startAbilityForResult()
方法,获得返回结果的回调为onAbilityResult()
。在Ability中调用setResult()
可以设置返回结果。
Service
模板的Ability (以下简称“Service”)主要用于后台运行任务(如执行音乐播放、文件下载等),但不提供用户交互界面。Service可由其他应用或Ability启动,即使用户切换到其他应用,Service仍将在后台继续运行。onStart()
: 该方法在创建Service的时候调用,用于Service的初始化。在Service的整个生命周期只会调用一次,调用时传入的Intent应为空。onCommand()
: 在Service创建完成之后调用,该方法在客户端每次启动该Service时都会调用,用户可以在该方法中做一些调用统计、初始化类的操作。public class ServiceAbility extends Ability {
@Override
public void onStart(lntent intent){
super.onStart(intent);
}
@Override
public void onCommand(Intent intent, boolean restart, intstartld) {
super.onCommand(intent, restart, startld);
}
@Override
public lRemoteObject onConnect(Intent intent){
super.onConnect(intent);
return null;
}
}
@Override
public void onDisconnect(Intentintent) {
super.onDisconnect(intent);
}
@Override
public void onStop() {
super.onStop();
}
Service也需要在应用配置文件中进行注册,注册类型type需要设置为service
{
"module": {
"abilities": [
{
"name": ".ServiceAbility",
"type": "service",
"visible": true
}
]
}
}
Ability为开发者提供了startAbility()
方法来启动另外一个Ability。因为Service也是Ability的一种,开发者同样可以通过将Intent传递给该方法来启动service。不仅支持启动本地Service,还支持启动远程Service。
开发者可以通过构造包含Deviceld、BundleName与AbilityName的Operation对象来设置目标Service信息。这三个参数的含义如下:
Deviceld
: 表示设备ID。如果是本地设备,则可以直接留空;如果是远程设备,可以通过ohos.distributedschedule.interwork.DeviceManagerr提供的getDeviceList
获取设备列表;
BundleName
: 表示包名称;AbilityName
:表示待启动的Ability名称。Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder().withDeviceld("").withBundleName("com.huawei.hiworld.himusic").withAbilityName("com.huawei.hiworld.himusic.ServiceAbility").build();
intent.setOperation(operation);
startAbility(intent);
Operation operation = new Intent.OperationBuilder()
.withDeviceld("deviceld")
.withBundleName("com.huawei.hiworld.himusic")
.withAbilityName("com.huawei.hiworld.himusic.ServiceAbility")//设置支持分布式调度系统多设备启动的标识
.withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE).build();
Intent intent = new Intent();
intent.setOperation(operation);
startAbility(intent);
startAbility的两种场景
执行上述代码后,Ability将通过startAbility()
方法来启动Service
onStart()
来初始化Service,再回调Service的onCommand()
方法来启动Service;onCommand()
方法来启动Service。connectAbility()
方法与其进行连接。
Intent
与AbilityConnection的实例
。AbilityConnection提供了两个方法供开发者实现:启动Service
: 该Service在其他Ability调用startAbility()
时创建,然后保持运行。其他Ability通过调用stopAbility()
来停止Service,Service停止后,系统会将其销毁。连接Service
: 该Service在其他Ability调用connectAbility()
时创建,客户端可通过调用disconnectAbility()
断开连接。多个客户端可以绑定到相同Service,而且当所有绑定全部取消后,系统即会销毁该Service。Service回调函数
前台Service
keepBackgroundRunning()
将Service与通知绑定。调用keepBackgroundRunning()
方法前需要在配置文件中声明ohos.permission.KEEP_BACKGROUND_RUNNING权限
backgroundModes参数
。cancelBackgroundRunning()
方法可停止前台service。//创建通知,其中1005为notificationld
NotificationRequest request = new NotificationRequest(1005);
NotificationRequest.NotificationNormalContent content = new NotificationRequest.NotificationNormalContent();
content.setTitle("title").setText("text");
NotificationRequest.NotificationContent notificationContent = new NotificationRequest.NotificationContent(content);
request.setContent(notificationContent);
//绑定通知,1005为创建通知时传入的notificationldkeepBackgroundRunning(1005, request);
{
"name": ".ServiceAbility",
"type": "service",
"visible": true,
"backgroundModes":["dataTransfer" ,"location"]
}
Operation
与Parameters
。内部结构
BundleName
与AbilityName
,则根据Ability的全称(例如,“ com.demoapp.FooAbility”)来直接启动应用,称为显式lntent
。隐式Intent
Intent设置属性时,必须先使用Operation来设置属性。如果需要新增或修改属性,必须在设置Operation后再执行操作。onStart()
回调的参数中获得intent对象Intent intent = new Intent();
/通过Intent中的OperationBuilder类构造operation对象,指定设备标识(空串表示当前设备)、应用包名、Ability名称
Operation operation = new lntent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.demoapp")
.withAbilityName("com.demoapp.FooAbility").build();
//把operation设置到intent中intent.setOperation(operation);startAbility(intent);
使用Intent进行数据传递
数据传输示例
·设FA1和FA2之间的Intent名为secondIntent,则数据传输代码如下:
请求方
startAbilityForResult()
方法发起请求。然后重写onAbilityResult()
回调方法,对请求结果进行处理。private void queryWeather() {
lntent 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"]
}
]
}
]
}
}
配置路由
以便支持以此action导航到对应的AbilitySlice@Override
protected void onStart(Intent intent){
addActionRoute(Intent.ACTION_QUERY_WEATHER, DemoSlice.class.getName());
}
setResult()
方法暂存返回结果。Override
protected void onActive() {
Intent resultIntent = new Intent();setResult(0, resultIntent);
}
前台FA有两个可视化元素,一个Text,用来显示获得的手机电量,一个Button,用来触发调用后台服务事件。
<Text
ohos:id="$+id:text_helloworld"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_ability_main"
ohos:layout_alignment="horizontal_center"
ohos:text="$string:mainability_HelloWorld"
ohos:text_size="20vp"
>
前端搭建
<Button
ohos:id="$+id:button_battery"
ohos:height="match_content"
ohos:width="match_content"
ohos:background_element="$graphic:background_ability_main"
ohos:layout_alignment="horizontal_center"
ohos:text="BatteryInfo"
ohos:text_size="30vp"
>
调用connectAbility(intent,connection)
连接后台服务,其中Intent的operation
参数已经指明服务所在设备id,包名和包含的能力名称,参数connection
为AbilityConnection类型。
private void startBatteryService() {
Operation operation = new Intent.OperationBuilder().withDeviceld("")
.withBundleName("com.whu.batteryjavacallpa")
.withAbilityName("com.whu.batteryjavacallpa.Batterylnfo").build();
Intent intent = new Intent();
intent.setOperation(operation);
connectAbility(intent, connection);
}
新建Service Ability,该服务没有界面,纯粹提供电量读取服务功能。该服务中除了基本的电量获取函数getBatteryInfo,最重要是完成Service Ability的重载函数onConnect(Intent intent)
。意味着当前台FA连接后台服务时会触发onConnect事件,在该事件中获取电量。
private String getBatteryInfo() {
StringBuilder stringBuilder = new StringBuilder();
boolean isCharging = getChargingStatus();
double batteryValue = getBatteryLevel();
stringBuilder
.append("电量还剩")
.append(batteryValue+"% ,"+ System.lineSeparator)).append("正在充电: "")
.append(isCharging);
}
return stringBuilder.toString();
}
lRemoteObject接口
@Override
public IRemoteObject onConnect(Intent intent){
MyRemote thisRemote = new MyRemote();
thisRemote.butery = getBatterylnfo();
return thisRemote;
}
,并返回给onConnect函数∶新建MyRemote类,MyRemote类为LocalRemoteObject的子类,而LocalRemoteObject为RemoteObject的子类。返回的MyRemote的实例会返回到客户端。
public class MyRemote extends LocalRemoteObject {
public String butery = "";//添加变量获取电量返回值
public MyRemote() {
super();
}
}
,显示电量:客户端重载IAbilityConnection
类的函数onAbilityConnectDone(ElementName elementName,lRemoteObject iRemoteObject,int resultCode)
,该函数在客户端与服务器连接建立好后会触发,服务端返回
lRemoteObject对象。解析该对象,得到手机电量。
private lAbilityConnection connection = new IAbilityConnection() {
@Override
public void onAbilityConnectDone(ElementName elementName, IKemoteubject likeolevu]eul, mresultCode){
HiLog.info(LABEL_LOG, "%{public]s" , "onAbilityConnectDone resultCode : " + resultCode);
MyRemote clientRemote = (MyRemote) iRemoteObject;
Text txt = (Text)findComponentByld(ResourceTable.ld_text_helloworld);
txt.setText(clientRemote.butery);
Button btn = (Button)findComponentByld(ResourceTable.ld_button_battery);
btn.setText("电池状态");
}
}
private lAbilityConnection connection = new IAbilityConnection() {
@Override
public void onAbilityConnectDone(ElementName elementName, IKemoteubject likeolevu]eul, mresultCode){
HiLog.info(LABEL_LOG, "%{public]s" , "onAbilityConnectDone resultCode : " + resultCode);
MyRemote clientRemote = (MyRemote) iRemoteObject;
Text txt = (Text)findComponentByld(ResourceTable.ld_text_helloworld);
txt.setText(clientRemote.butery);
Button btn = (Button)findComponentByld(ResourceTable.ld_button_battery);
btn.setText("电池状态");
}
}
[外链图片转存中…(img-OtjTEBCm-1642394987751)]