HarmonyOS鸿蒙Next开发者学习笔记
HarmonyOS鸿蒙Next开发者学习笔记
Ability
Ability
概述
Ability可分为 FA(Feature Ability)和 PA(Particle Ability)。
FA(Feature Ability)
- 支持 Page Ability( 用户交互 )
PA(Particle Ability)
- 支持 Service Ability(后台运行任务 )
- 支持 Data Ability(对外部提供统一的数据访问 )
Page Ability
概念
setMainRoute()
指定默认展示的AbilitySlice。addActionRoute()
更改默认展示的AbilitySlice。
public class MyAbility extends Ability {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
setMainRoute(MainSlice.class.getName());
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()
:首次创建Page实例时触发,进入INACTIVE状态。onActive()
:Page进入前台时调用,进入ACTIVE状态。onInactive()
:Page失去焦点时调用,进入INACTIVE状态。onBackground()
:Page不再对用户可见时调用,进入BACKGROUND状态。onForeground()
:Page重新回到前台时调用。onStop()
:系统将要销毁Page时调用。
@Override
public void onStart(Intent intent) {
super.onStart(intent);
setMainRoute(FooSlice.class.getName());
}
@Override
public void onActive() {
super.onActive();
// 获取在onInactive()中被释放的资源。
}
@Override
public void onInactive() {
super.onInactive();
// 实现Page失去焦点时应表现的恰当行为。
}
@Override
public void onBackground() {
super.onBackground();
// 释放Page不可见时无用的资源。
}
@Override
public void onForeground() {
super.onForeground();
// 重新申请在onBackground()中释放的资源。
}
@Override
public void onStop() {
super.onStop();
// 通知用户进行系统资源的释放。
}
AbilitySlice生命周期
AbilitySlice和Page具有相同的生命周期状态和同名的回调。
必须重写AbilitySlice的onStart()
回调,并在此方法中通过setUIContent()
方法设置页面:
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
setUIContent(ResourceTable.Layout_main_layout);
}
Page与AbilitySlice生命周期关联
当AbilitySlice处于前台且具有焦点时,其生命周期状态随着所属Page的生命周期状态的变化而变化。
AbilitySlice间导航
同一Page内导航
通过present()
方法实现导航。
@Override
protected void onStart(Intent intent) {
...
Button button = ...;
button.setClickedListener(listener -> present(new TargetSlice(), new Intent()));
...
}
从导航目标AbilitySlice返回时,能够获得其返回结果时,使用presentForResult()
实现导航。
@Override
protected void onStart(Intent intent) {
...
Button button = ...;
button.setClickedListener(listener -> presentForResult(new TargetSlice(), new Intent(), 0));
...
}
系统将回调onResult()
来接收和处理返回结果,需要重写该方法。
@Override
protected void onResult(int requestCode, Intent resultIntent) {
if (requestCode == 0) {
// Process resultIntent here.
}
}
不同Page间导航
AbilitySlice相互不可见,无法通过present()
或presentForResult()
方法直接导航到其他Page的AbilitySlice。
可以通过配置Intent的Action导航到目标AbilitySlice。
Page间的导航可以使用startAbility()
或startAbilityForResult()
方法,获得返回结果的回调为onAbilityResult()
。
跨设备迁移
实现IAbilityContinuation接口
onStartContinuation()
:Page请求迁移后,系统首先回调此方法,在此回调中决策当前是否可以执行迁移。onSaveData()
:如果onStartContinuation()
返回true,则系统回调此方法,在此回调中保存必须传递到另外设备上以便恢复Page状态的数据。onRestoreData()
:源侧设备上Page完成保存数据后,系统在目标侧设备上回调此方法,在此回调中接受用于恢复Page状态的数据。onCompleteContinuation()
:目标侧设备上恢复数据一旦完成,系统就会在源侧设备上回调Page的此方法,可以在此检查迁移结果是否成功,并在此处理迁移结束的动作。onRemoteTerminated()
:如果开发者使用continueAbilityReversibly()
而不是continueAbility()
,则此后可以在源侧设备上使用reverseContinueAbility()
进行回迁。
请求迁移
try {
continueAbility();
} catch (IllegalStateException e) {
// Maybe another continuation in progress.
...
}
try {
continueAbilityReversibly();
} catch (IllegalStateException e) {
// Maybe another continuation in progress.
...
}
请求回迁
Service Ability
概念
用于后台运行任务,不提供用户交互界面,在后台运行。
是单例的,须在Service里创建新的线程来处理,防止造成主线程阻塞,应用程序无响应。
创建
- 创建Ability的子类,实现Service相关的生命周期方法。
public class ServiceAbility extends Ability {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
}
@Override
public void onCommand(Intent intent, boolean restart, int startId) {
super.onCommand(intent, restart, startId);
}
@Override
public IRemoteObject onConnect(Intent intent) {
super.onConnect(intent);
return null;
}
@Override
public void onDisconnect(Intent intent) {
super.onDisconnect(intent);
}
@Override
public void onStop() {
super.onStop();
}
}
- 注册Service
{
"module": {
"abilities": [
{
"name": ".ServiceAbility",
"type": "service",
"visible": true
}
]
}
}
启动
通过startAbility()
方法来启动Service。
Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.huawei.hiworld.himusic")
.withAbilityName("com.huawei.hiworld.himusic.entry.ServiceAbility")
.build();
intent.setOperation(operation);
startAbility(intent);
连接
通过connectAbility()
方法与其进行连接。
private IAbilityConnection connection = new IAbilityConnection() {
@Override
public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {
// 在这里开发者可以拿到服务端传过来IRemoteObject对象,从中解析出服务端传过来的信息
}
@Override
public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {
}
};
connectAbility(intent, connection);
声明周期
启动Service
该Service在其他Ability调用startAbility()
时创建,然后保持运行。
其他Ability通过调用stopAbility()
来停止Service,Service停止后,系统会将其销毁。
连接Service
该Service在其他Ability调用connectAbility()
时创建,客户端可通过调用disconnectAbility()
断开连接。
多个客户端可以绑定到相同Service,而且当所有绑定全部取消后,系统即会销毁该Service。
前台Service
只需在Service创建的方法里,调用keepBackgroundRunning()
将Service与通知绑定。
// 创建通知,其中1005为notificationId
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为创建通知时传入的notificationId
keepBackgroundRunning(1005, request);
在配置文件中配置如下:
{
"name": ".ServiceAbility",
"type": "service",
"visible": true,
"backgroundModes": ["dataTransfer", "location"]
}
Data Ability
概念
管理其自身和其他应用存储数据的访问,并提供与其他应用共享数据。
概念
- URI介绍:
Scheme://[authority]/[path][?query][#fragment]
- scheme:协议方案名,固定为"dataability",代表Data Ability所使用的协议类型。
- authority:设备ID,如果为跨设备场景,则为目的设备的IP地址;如果为本地设备场景,则不需要填写。
- path:资源的路径信息,代表特定资源的位置信息。
- query:查询参数。
- fragment:可以用于指示要访问的子资源。
例:
- 跨设备场景:
dataability://device_id/com.huawei.dataability.persondata/person/10
- 本地设备:
dataability:///com.huawei.dataability.persondata/person/10
访问
可通过DataAbilityHelper
类来访问当前应用或其他应用提供的共享数据。
声明使用权限
{
"reqPermissions": [
{
"name": "com.example.myapplication5.DataAbility.DATA"
}
]
}
创建DataAbilityHelper
DataAbilityHelper helper = DataAbilityHelper.creator(this);
访问Data Ability
访问文件
FileDescriptor openFile(Uri uri, String mode)
方法来操作文件。
FileDescriptor fd = helper.openFile(uri, "r");
FileInputStream fis = new FileInputStream(fd);
访问数据库
增、删、改、查以及批量处理等方法来操作数据库。
ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates)
int insert(Uri uri, ValuesBucket value)
int batchInsert(Uri uri, ValuesBucket[] values)
int delete(Uri uri, DataAbilityPredicates predicates)
int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates)
DataAbilityResult[] executeBatch(ArrayList<DataAbilityOperation> operations)
DataAbilityHelper helper = DataAbilityHelper.creator(this);
DataAbilityPredicates predicates = new DataAbilityPredicates();
predicates.between("userId", 101, 103);
ResultSet resultSet = helper.query(uri, columns, predicates);
resultSet.goToFirstRow();
do {
// 在此处理ResultSet中的记录;
}while(resultSet.goToNextRow());
DataAbilityHelper helper = DataAbilityHelper.creator(this);
ValuesBucket valuesBucket = new ValuesBucket();
valuesBucket.putString("name", "Tom");
valuesBucket.putInteger("age", 12);
helper.insert(uri, valuesBucket);
DataAbilityHelper helper = DataAbilityHelper.creator(this);
ValuesBucket[] values = new ValuesBucket[2];
values[0] = new ValuesBucket();
values[0].putString("name", "Tom");
values[0].putInteger("age", 12);
values[1] = new ValuesBucket();
values[1].putString("name", "Tom1");
values[1].putInteger("age", 16);
helper.batchInsert(uri, values);
DataAbilityHelper helper = DataAbilityHelper.creator(this);
DataAbilityPredicates predicates = new DataAbilityPredicates();
predicates.between("userId", 101, 103);
helper.delete(uri, predicates);
DataAbilityHelper helper = DataAbilityHelper.creator(this);
DataAbilityPredicates predicates = new DataAbilityPredicates();
predicates.equalTo("userId", 102);
ValuesBucket valuesBucket = new ValuesBucket();
valuesBucket.putString("name", "Tom");
valuesBucket.putInteger("age", 12);
helper.update(uri, valuesBucket, predicates);
DataAbilityHelper helper = DataAbilityHelper.creator(this);
ValuesBucket value1 = initSingleValue();
DataAbilityOperation opt1 = DataAbilityOperation.newInsertBuilder(insertUri).withValuesBucket(value1).build();
ValuesBucket value2 = initSingleValue2();
DataAbilityOperation opt2 = DataAbilityOperation.newInsertBuilder(insertUri).withValuesBucket(value2).build();
ArrayList<DataAbilityOperation> operations = new ArrayList<>();
operations.add(opt1);
operations.add(opt2);
DataAbilityResult[] result = helper.executeBatch(insertUri, operations);
创建
需要为应用添加一个或多个Ability的子类,来提供程序与其他应用之间的接口。
需要首先确定好使用何种类型的数据。
确定数据存储方式
- 文件数据:如文本、图片、音乐等。
- 结构化数据:如数据库等。
实现UserDataAbility
文件存储
重写FileDescriptor openFile(Uri uri, String mode)
方法来操作文件。
MessageParcel messageParcel = MessageParcel.obtain();
File file = new File(uri.getDecodedPathList().get(1));
if (mode == null || !"rw".equals(mode)) {
file.setReadOnly();
}
FileInputStream fileIs = new FileInputStream(file);
FileDescriptor fd = fileIs.getFD();
return messageParcel.dupFileDescriptor(fd);
数据库存储
初始化数据库连接。
private static final String DATABASE_NAME = "UserDataAbility.db";
private static final String DATABASE_NAME_ALIAS = "UserDataAbility";
private OrmContext ormContext = null;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
DatabaseHelper manager = new DatabaseHelper(this);
ormContext = manager.getOrmContext(DATABASE_NAME_ALIAS, DATABASE_NAME, BookStore.class);
}
编写数据库操作方法。
public ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates) {
if (ormContext == null) {
HiLog.error(this.getClass().getSimpleName(), "failed to query, ormContext is null");
return null;
}
OrmPredicates ormPredicates = DataAbilityUtils.createOrmPredicates(predicates, User.class);
ResultSet resultSet = ormContext.query(ormPredicates, columns);
if (resultSet == null) {
HiLog.info(getClass(), "resultSet is null");
}
return resultSet;
}
public int insert(Uri uri, ValuesBucket value) {
if (ormContext == null) {
HiLog.error(getClass().getSimpleName(), "failed to insert, ormContext is null");
return -1;
}
String path = uri.getPath();
if (buildPathMatcher().getPathId(path) != PathId) {
HiLog.info(getClass(), "UserDataAbility insert path is not matched");
return -1;
}
User user = new User();
user.setUserId(value.getInteger("userId"));
user.setFirstName(value.getString("firstName"));
user.setLastName(value.getString("lastName"));
user.setAge(value.getInteger("age"));
user.setBalance(value.getDouble("balance"));
boolean isSuccessed = true;
try {
isSuccessed = ormContext.insert(user);
} catch (DataAbilityRemoteException e) {
HiLog.error(TAG, "insert fail: " + e.getMessage());
throw new RuntimeException(e);
}
if (!isSuccessed) {
HiLog.error(getClass().getSimpleName(), "failed to insert");
return -1;
}
isSuccessed = ormContext.flush();
if (!isSuccessed) {
HiLog.error(getClass().getSimpleName(), "failed to insert flush");
return -1;
}
DataAbilityHelper.creator(this, uri).notifyChange(uri);
int id = Math.toIntExact(user.getRowId());
return id;
}
注册UserDataAbility
{
"name": ".UserDataAbility",
"type": "data",
"visible": true,
"uri": "dataability://com.example.myapplication5.DataAbilityTest",
"permissions": [
"com.example.myapplication5.DataAbility.DATA"
]
}
Intent
基本概念
Intent是对象之间传递信息的载体。
Intent的构成元素包括Operation与Parameters。
- Operation
- Action:表示动作,通常使用系统预置Action,应用也可以自定义Action。
- Entity:表示类别,通常使用系统预置Entity,应用也可以自定义Entity。
- Uri:表示Uri描述。
- Flags:表示处理Intent的方式。
- BundleName:表示包描述。
- AbilityName:表示待启动的Ability名称。
- DeviceId:表示运行指定Ability的设备ID。
- Parameters:一种支持自定义的数据结构,开发者可以通过Parameters传递某些请求所需的额外信息。
当Intent用于发起请求时,根据指定元素的不同,分为两种类型:
- 如果同时指定了BundleName与AbilityName,则根据Ability的全称(例如,“com.demoapp.FooAbility”)来直接启动应用。
- 如果未同时指定BundleName和AbilityName,则根据Operation中的其他属性来启动应用。
根据Ability的全称启动应用
通过构造包含BundleName与AbilityName的Operation对象,可以启动一个Ability、并导航到该Ability。
Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")
.withBundleName("com.demoapp")
.withAbilityName("com.demoapp.FooAbility")
.build();
intent.setOperation(operation);
startAbility(intent);
根据Operation的其他属性启动应用
请求方
在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);
...
}
更多关于HarmonyOS鸿蒙Next开发者学习笔记的实战教程也可以访问 https://www.itying.com/category-93-b0.html
HarmonyOS鸿蒙Next开发者学习笔记主要涉及以下内容:
系统架构
鸿蒙Next采用分布式架构,支持多设备协同,包括手机、平板、智能穿戴等。其核心是分布式软总线、分布式数据管理和分布式任务调度。
开发框架
鸿蒙Next提供ArkUI框架,支持声明式UI开发,简化界面设计。ArkTS是推荐的开发语言,基于TypeScript,增强类型安全和开发效率。
分布式能力
鸿蒙Next强调设备间的无缝连接,支持跨设备调用服务、共享数据和协同任务。开发者可以利用分布式API实现多设备间的交互。
安全机制
鸿蒙Next内置多层安全防护,包括应用沙箱、数据加密和权限管理,确保用户数据和应用的安全性。
开发工具
DevEco Studio是官方推荐的集成开发环境,支持代码编写、调试和模拟器测试,提供丰富的模板和插件,提升开发效率。
生态支持
鸿蒙Next积极构建开发者生态,提供丰富的API和文档,支持第三方应用快速接入,推动系统生态的扩展和完善。
这些内容涵盖了鸿蒙Next的核心技术和开发要点,帮助开发者快速上手并构建高效、安全的分布式应用。