鸿蒙 Ability 讲解(页面生命周期、后台服务(1),某大厂开发者对于HarmonyOS鸿蒙多线程的总结

//设置通知的标题和内容

content.setTitle(“Title”).setText(“Text”);

//创建通知内容

NotificationRequest.NotificationContent notificationContent = new

NotificationRequest.NotificationContent(content);

//设置通知

request.setContent(notificationContent);

keepBackgroundRunning(1005,request);

HiLog.error(LABEL_LOG, “ServiceAbility::startupForegroundService”);

}

然后在onStart中调用。

在这里插入图片描述

别忘了在config.json中给相关的代码配置:

在这里插入图片描述

然后直接运行到主页面,之后会先启动Service,然后将Service变成前台服务。运行之后如下:

在这里插入图片描述

说实话目前也就只是日志打印出来了,但是我也不知道当前这个服务是不是在前台。

然后在onCommand中取消前台服务:

@Override

public void onCommand(Intent intent, boolean restart, int startId) {

HiLog.error(LABEL_LOG, “ServiceAbility::onCommand”);

cancelBackgroundRunning();

HiLog.error(LABEL_LOG, “ServiceAbility::cancelBackgroundRunning”);

}

再运行一次。

在这里插入图片描述

四、Data Ability讲解


使用 Data 模板的 Ability(以下简称“Data”)有助于应用管理其自身和其他应用存储数据的访问,并提供与其他应用共享数据的方法。Data 既可用于同设备不同应用的数据共享,也支持跨设备不同应用的数据共享。

数据的存放形式多样,可以是数据库,也可以是磁盘上的文件。Data 对外提供对数据的增、删、改、查,以及打开文件等接口,这些接口的具体实现由开发者提供。说起来和Android的ContentProvider有些像。

① URI 介绍

Data 的提供方和使用方都通过 URI(Uniform Resource Identifier)来标识一个具体的数据,例如数据库中的某个表或磁盘上的某个文件。HarmonyOS 的 URI 仍基于 URI 通用标准,格式如下:

  • scheme:协议方案名,固定为“dataability”,代表 Data Ability 所使用的协议类型。

  • authority:设备 ID,如果为跨设备场景,则为目的设备的 IP 地址;如果为本地设备场景,则不需要填写。

  • path:资源的路径信息,代表特定资源的位置信息。

  • query:查询参数。

  • fragment:可以用于指示要访问的子资源。

URI 示例:

  • 跨设备场景:dataability://device_id/com.huawei.dataability.persondata/person/10

  • 本地设备:dataability:///com.huawei.dataability.persondata/person/10

② 访问 Data和声明使用权限

开发者可以通过 DataAbilityHelper 类来访问当前应用或其他应用提供的共享数据。

DataAbilityHelper 作为客户端,与提供方的 Data 进行通信。Data 接收到请求后,执行相应的处理,并返回结果。DataAbilityHelper 提供了一系列与 Data Ability 对应的方法。

如果待访问的 Data 声明了访问需要权限,则访问此 Data 需要在配置文件中声明需要此权限。比如

在这里插入图片描述

reqPermissions 表示应用运行时向系统申请的权限。

说了这么多还是来创建一个Data Ability吧,鼠标右键包名 → New → Ability → Empty Data Ability

在这里插入图片描述

这个的Visible和Service的Visible是同样的意思,勾选上就是运行其他应用程序访问数据。

在这里插入图片描述

然后打开config.json,看创建DataAbility时,自动生成了那些代码。

在这里插入图片描述

可以看到type为“data”,另外还自带一个提供给外部数据的权限,已经访问这个DataAbility的uri。

然后看一下DataAbility的代码:

package com.llw.helloworld;

import ohos.aafwk.ability.Ability;

import ohos.aafwk.content.Intent;

import ohos.data.resultset.ResultSet;

import ohos.data.rdb.ValuesBucket;

import ohos.data.dataability.DataAbilityPredicates;

import ohos.hiviewdfx.HiLog;

import ohos.hiviewdfx.HiLogLabel;

import ohos.utils.net.Uri;

import ohos.utils.PacMap;

import java.io.FileDescriptor;

public class DataAbility extends Ability {

private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, “Demo”);

@Override

public void onStart(Intent intent) {

super.onStart(intent);

HiLog.info(LABEL_LOG, “ProviderAbility onStart”);

}

@Override

public ResultSet query(Uri uri, String[] columns, DataAbilityPredicates predicates) {

return null;

}

@Override

public int insert(Uri uri, ValuesBucket value) {

HiLog.info(LABEL_LOG, “ProviderAbility insert”);

return 999;

}

@Override

public int delete(Uri uri, DataAbilityPredicates predicates) {

return 0;

}

@Override

public int update(Uri uri, ValuesBucket value, DataAbilityPredicates predicates) {

return 0;

}

@Override

public FileDescriptor openFile(Uri uri, String mode) {

return null;

}

@Override

public String[] getFileTypes(Uri uri, String mimeTypeFilter) {

return new String[0];

}

@Override

public PacMap call(String method, String arg, PacMap extras) {

return null;

}

@Override

public String getType(Uri uri) {

return null;

}

}

在创建的时候就生成了一些代码,基本的增删改查、打开文件、获取URI类型、获取文件类型、还有一个回调。再加上一个onStart方法,总共是9个,乍一看比较多。下面先来介绍 DataAbilityHelper 具体的使用步骤。

创建 DataAbilityHelper

DataAbilityHelper 为开发者提供了 creator()方法来创建 DataAbilityHelper 实例。该方法为静态方法,有多个重载。最常见的方法是通过传入一个 context 对象来创建DataAbilityHelper 对象。

在这里插入图片描述

DataAbilityHelper 为开发者提供了一系列的接口来访问不同类型的数据(文件、数据库等)。

  • 访问文件

DataAbilityHelper 为开发者提供了 FileDescriptor openFile(Uri uri, String mode)方法来操作文件。此方法需要传入两个参数,其中 uri 用来确定目标资源路径,mode 用来指定打开文件的方式,可选方式包含“r”(读), “w”(写), “rw”(读写),“wt”(覆盖写),“wa”(追加写),“rwt”(覆盖写且可读)。该方法返回一个目标文件的 FD(文件描述符),把文件描述符封装成流,开发者就可以对文件流进行自定义处理。比如:

// 读取文件描述符

try {

//通过文件描述符 读取指定uri的文件 ,“r”(读), “w”(写), “rw”(读写),“wt”(覆盖写),“wa”(追加写),“rwt”(覆盖写且可读)

FileDescriptor fileDescriptor = helper.openFile(Uri.parse(“dataability://com.llw.helloworld.DataAbility”),“r”);

//获取文件输入流

FileInputStream fileInputStream = new FileInputStream(fileDescriptor);

} catch (DataAbilityRemoteException e) {

e.printStackTrace();

} catch (FileNotFoundException e) {

e.printStackTrace();

}

  • 访问数据库

DataAbilityHelper 为开发者提供了增、删、改、查以及批量处理等方法来操作数据库。

下面代码来说明一下:

  • query 查询方法,其中 uri 为目标资源路径,columns 为想要查询的字段。开发者的查询条件可以通过 DataAbilityPredicates 来构建。查询用户表中 id 在 1-10 之间的用户的年龄,并把结果打印出来,代码示例如下:

/**

  • 查询

*/

private void queryData(DataAbilityHelper helper) {

//构建uri

Uri uri = Uri.parse(“dataability://com.llw.helloworld.DataAbility”);

//构建查询字段

String[] column = {“age”};

// 构造查询条件

DataAbilityPredicates predicates = new DataAbilityPredicates();

//查询用户id在1~10之间的数据

predicates.between(“userId”,1,10);

//进行查询

try {

//用一个结果集来接收查询返回的数据

ResultSet resultSet = helper.query(uri,column,predicates);

//从第一行开始

resultSet.goToFirstRow();

//处理每一行的数据

do {

// 在此处理 ResultSet 中的记录

HiLog.info(LABEL_LOG, resultSet.toString());

}while (resultSet.goToNextRow());

} catch (DataAbilityRemoteException e) {

e.printStackTrace();

}

}

  • insert 插入方法,其中 uri 为目标资源路径,ValuesBucket 为要新增的对象。插入一条用户信息的代码示例如下:

/**

  • 插入 单条数据

*/

private void insertData(DataAbilityHelper helper) {

//构建uri

Uri uri = Uri.parse(“dataability://com.llw.helloworld.DataAbility”);

// 构造插入数据

ValuesBucket valuesBucket = new ValuesBucket();

valuesBucket.putString(“name”,“KaCo”);

valuesBucket.putInteger(“age”,24);

try {

helper.insert(uri,valuesBucket);

} catch (DataAbilityRemoteException e) {

e.printStackTrace();

}

}

  • batchInsert 批量插入方法,和 insert()类似。批量插入用户信息的代码示例如下:

/**

  • 插入 多条数据

  • @param helper 数据帮助类

*/

private void batchInsertData(DataAbilityHelper helper) {

//构建uri

Uri uri = Uri.parse(“dataability://com.llw.helloworld.DataAbility”);

// 构造插入数据

ValuesBucket[] valuesBuckets = new ValuesBucket[3];

//构建第一条数据

valuesBuckets[0] = new ValuesBucket();

valuesBuckets[0].putString(“name”,“Jim”);

valuesBuckets[0].putInteger(“age”,18);

//构建第二条数据

valuesBuckets[1] = new ValuesBucket();

valuesBuckets[1].putString(“name”,“Tom”);

valuesBuckets[1].putInteger(“age”,20);

//构建第三条数据

valuesBuckets[2] = new ValuesBucket();

valuesBuckets[2].putString(“name”,“Kerry”);

valuesBuckets[2].putInteger(“age”,24);

try {

//批量插入数据

helper.batchInsert(uri,valuesBuckets);

} catch (DataAbilityRemoteException e) {

e.printStackTrace();

}

}

  • delete 删除方法,其中删除条件可以通过 DataAbilityPredicates 来构建。删除用户表中 id 在 1-10 之间的用户,代码示例如下:

/**

  • 删除数据

  • @param helper 数据帮助类

*/

private void deleteData(DataAbilityHelper helper) {

//构建uri

Uri uri = Uri.parse(“dataability://com.llw.helloworld.DataAbility”);

// 构造删除条件

DataAbilityPredicates predicates = new DataAbilityPredicates();

//用户id在1~10的数据

predicates.between(“userId”,1,10);

try {

//删除

helper.delete(uri,predicates);

} catch (DataAbilityRemoteException e) {

e.printStackTrace();

}

}

  • update 更新方法,更新数据由 ValuesBucket 传入,更新条件由 DataAbilityPredicates 来构建。更新 id 为 2 的用户,代码示例如下:

/**

  • 更新数据

  • @param helper 数据帮助类

*/

private void updateData(DataAbilityHelper helper) {

//构造uri

Uri uri = Uri.parse(“dataability://com.llw.helloworld.DataAbility”);

//构造更新数据

ValuesBucket valuesBucket = new ValuesBucket();

valuesBucket.putString(“name”,“Aoe”);

valuesBucket.putInteger(“age”,66);

//构造更新条件

DataAbilityPredicates predicates = new DataAbilityPredicates();

//userId为2的用户

predicates.equalTo(“userId”,2);

try {

//更新数据

helper.update(uri,valuesBucket,predicates);

} catch (DataAbilityRemoteException e) {

e.printStackTrace();

}

}

  • executeBatch 此方法用来执行批量操作。DataAbilityOperation 中提供了设置操作类型、数据和操作条件的方法,开发者可自行设置自己要执行的数据库操作。插入多条数据的代码示例如下:

/**

  • 批量操作数据

  • @param helper 数据帮助类

*/

private void executeBatchData(DataAbilityHelper helper) {

//构造uri

Uri uri = Uri.parse(“dataability://com.llw.helloworld.DataAbility”);

//构造批量操作

//第一个

ValuesBucket valuesBucket1 = new ValuesBucket();

valuesBucket1.putString(“name”,“Karen”);

valuesBucket1.putInteger(“age”,24);

//构建批量插入

DataAbilityOperation operation1 = DataAbilityOperation.newInsertBuilder(uri).withValuesBucket(valuesBucket1).build();

//第二个

ValuesBucket valuesBucket2 = new ValuesBucket();

valuesBucket2.putString(“name”,“Leo”);

valuesBucket2.putInteger(“age”,48);

DataAbilityOperation operation2 = DataAbilityOperation.newInsertBuilder(uri).withValuesBucket(valuesBucket2).build();

ArrayList operations = new ArrayList<>();

operations.add(operation1);

operations.add(operation2);

try {

//获取批量操作数据的结果

DataAbilityResult[] results = helper.executeBatch(uri,operations);

HiLog.debug(LABEL_LOG,results.length+“”);

} catch (DataAbilityRemoteException e) {

e.printStackTrace();

} catch (OperationExecuteException e) {

e.printStackTrace();

}

}

③ 创建Data

确定数据存储方式

确定数据的存储方式,Data 支持以下两种数据形式:

  • 文件数据:如文本、图片、音乐等。

  • 结构化数据:如数据库等。

下面创建一个UserDataAbility,注意勾选上Visible

在这里插入图片描述

实现 UserDataAbility

UserDataAbility 接收其他应用发送的请求,提供外部程序访问的入口,从而实现应用间的数据访问。Data 提供了文件存储和数据库存储两组接口供用户使用。

文件存储

开发者需要在 Data 中重写 FileDescriptor openFile(Uri uri, String mode)方法来操作文件:uri 为客户端传入的请求目标路径;mode 为开发者对文件的操作选项,可选方式包含“r”(读), “w”(写), “rw”(读写)等。

MessageParcel 类提供了一个静态方法,用于获取 MessageParcel 实例。通过dupFileDescriptor()函数复制待操作文件流的文件描述符,并将其返回,供远端应用使用。示例,根据传入uri打开对应的文件,在UserDataAbility中写入如下方法

/**

  • uri 打开对应的文件

*/

private void openUriFile() {

//构建uri

Uri uri = Uri.parse(“dataability://com.llw.helloworld.UserDataAbility”);

//获取文件 通过uri获取解码路径列表的第2条数据

File file = new File(uri.getDecodedPathList().get(1));

//只读

file.setReadOnly();

try {

//文件输入流

FileInputStream fileInputStream = new FileInputStream(file);

//得到文件描述符

FileDescriptor fileDescriptor = fileInputStream.getFD();

//绑定文件描述符

MessageParcel.dupFileDescriptor(fileDescriptor);

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

数据库存储

初始化数据库连接。系统会在应用启动时调用 onStart()方法创建 Data 实例。在此方法中,开发者应该创建数据库连接,并获取连接对象,以便后续和数据库进行操作。为了避免影响应用启动速度,开发者应当尽可能将非必要的耗时任务推迟到使用时执行,而不是在此方法中执行所有初始化。示例:

  • 初始化的时候连接数据库。

首先要创建一个数据实体bean

package com.llw.helloworld;

import ohos.data.orm.OrmObject;

public class BookStore extends OrmObject {

private int id;

private String bookName;

private double price;

private int page;

private String author;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getBookName() {

return bookName;

}

public void setBookName(String bookName) {

this.bookName = bookName;

}

public double getPrice() {

return price;

}

public void setPrice(double price) {

this.price = price;

}

public int getPage() {

return page;

}

public void setPage(int page) {

this.page = page;

}

public String getAuthor() {

return author;

}

public void setAuthor(String author) {

this.author = author;

}

}

然后在UserDataAbility中如下:

在这里插入图片描述

上面的代码是官方文档里面的,可以看到这里是有一个地方报错的,因为少了一个参数,然后看一下getOrmContext方法少什么参数。

在这里插入图片描述

然后来看一下OrmMigration的源码

在这里插入图片描述

这是一个抽象类,可以通过继承的方式去实现它里面的方法。

下面我创建一个TestOrmContext1继承OrmMigration,里面的代码如下:

package com.llw.helloworld;

import ohos.data.orm.OrmMigration;

import ohos.data.rdb.RdbStore;

public class TestOrmContext1 extends OrmMigration {

/**

  • 此处用于配置数据库版本迁移的开始版本和结束版本,

  • super(startVersion, endVersion)即数据库版本号从 1 升到 2。

*/

public TestOrmContext1() {

super(1, 2);

}

/**

  • 迁移时

  • @param rdbStore

*/

@Override

public void onMigrate(RdbStore rdbStore) {

rdbStore.executeSql(“ALTER TABLE BookStore ADD COLUMN addColumn1 INTEGER”);

}

}

其实这个方法的意思就是在连接数据库的时候查询数据库的版本,决定是否要升级。

因为加了也报错,那么我为什么不加上去呢?你以为加上去就不报错了吗?我是不得其解,也许是我才疏学浅吧。

在这里插入图片描述

  • 编写数据库操作方法

Ability 定义了 6 个方法供用户处理对数据库表数据的增删改查。

先创建一个用户的实体

package com.llw.helloworld;

public class User extends OrmObject {

private int id;

private String name;

private int age;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

  • query 该方法接收三个参数,分别是查询的目标路径,查询的列名,以及查询条件,查询条件由类DataAbilityPredicates 构建。根据传入的列名和查询条件查询用户表的代码示例如下:

在这里插入图片描述

可以看到创建Data Ability的时候就会自动生成这个方法,下面的代码就在这个方法里面写:

/**

  • 查询数据库

  • @param uri 目标uri

  • @param columns 查询的字段

  • @param predicates 查询的条件

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a2900051490e90bca48e8e74c632a4b3.png#pic_center)

可以看到创建Data Ability的时候就会自动生成这个方法,下面的代码就在这个方法里面写:

/**

  • 查询数据库

  • @param uri 目标uri

  • @param columns 查询的字段

  • @param predicates 查询的条件

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-hecTpk5o-1712805152552)]
[外链图片转存中…(img-LQJWxW05-1712805152552)]
[外链图片转存中…(img-R9sYJbX8-1712805152553)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
[外链图片转存中…(img-jzyuNbTi-1712805152553)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值