HarmonyOS数据持久化

内容纲要

Data Ability

  • 使用Data模板的Ability有助于应用管理自身和其他应用存储数据的访问,并提供与其他应用共享数据的方法。Data既可用于同设备不同应用的数据共享,也支持跨设备不同应用的数据共享
  • Data对外提供对数据的增、删、改、查以及打开文件等接口,接口具体实现由开发者提供

确定数据存储方式

  • Data支持两种数据形式:
    • 文件数据:文本、图片、音乐等
    • 结构化数据:数据库等

Data Ability数据库操作服务

  • Ability定义了6个方法供用户处理对数据库表数据的操作。这6个方法在Ability中已默认实现,开发者可按需重写
方法描述
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 values, DataAbility, DataAbilityPredicates predicates)更新数据库
DataAbilityResult[] executeBatch(ArrayList operation)批量操作数据库

实现UserDataAbility

  • UserDataAbility用于接收其他应用发送的请求,提供外部程序访问的入口,从而实现应用间的数据访问
  • 实现UserDataAbility,需要在“Project”窗口当前工程的主目录(“entry > src > main > java > com.xxx.xxx”)选择“File > New > Ability > Empty Data Ability”,设置"Data Name"后完成UserDataAbility的创建
  • Data提供了文件存储数据库存储两组接口供使用

注册UserDataAbility

  • 与Service Ability类似
  • 配置文件中该字段在创建Data Ability时自动创建,name与创建的Data Ability一致
  • 需关注以下属性
    • type:类型设置为data
    • uri:对外提供的访问路径,全局唯一
    • permissions:访问该data ability时需要申请的访问权限

config.json中的Data Ability

{
        "name": ".UserDataAbility",
        "type": "data",
        "visible": "true",
        "uri": "dataability://com.example.myapplication5.DataAbilityTest",
        "permissions": ["com.example.myapplication5.DataAbility.DATA"]
}

URI

  • Data的提供方和使用方都通过URI标识一个具体数据,如数据库中的某个表或磁盘上的某个文件。URI通用标准如下:

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

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

格式解析

  • scheme:协议方案名,固定为"dataability",代表Data Ability所使用的协议类型
  • authority:设备ID。如果为跨设备场景,则为目标设备ID;如果为本地设备场景,则不用填写
  • path:资源的路径信息,代表特定资源的位置信息
  • query:查询参数
  • fragment:可用于指示要访问的子资源

文件存储

  • 开发者需在Data中重写FileDescriptor openFile(Uri uri, String mode)方法操作文件:uri为客户端传入目标请求路径;mode为开发者对文件的操作选项,可选方式包含r、w、rw、wt、wa、rwt
  • ohos.rpc.MessageParcel类提供了一个静态方法,用于获取MessageParcel实例。开发者可通过获取到的MessageParcel实例,使用dupFileDescriptor()函数复制待操作文件流的文件描述符,并将其返回,供远端应用访问文件

打开文件

  • 根据传入的uri打开对应文件

    @Override
    public FIleDescriptor openFile(Uri uri, String mode) throws File NotFoundException
    {
        // 创建messageParcel
        MessageParcel messageParcel= MessageParcel.obtain();
        File file = new File(uri.getDecodedPathList().get(1));
        if (mode == null || !"rw".equals(mode))
        {
                file.setReadOnly();
        }
        FileInputStream filels = new FileInputStream(file);
        FIleDescriptor fd = filels.getFD();
    
        // 绑定文件描述符
        return messageParcel.dupFileDescriptor(fd);
    }

    访问Data

  • 开发者可通过DataAbilityHelper类访问当前应用或其他应用提供的共享数据。DataAbilityHelper作为客户端,与提供方的Data进行通信。Data接收到请求后,执行相应处理并返回结果。DataAbilityHelper提供了一系列与Data Ability对应的方法,步骤如下:

声明使用权限

  1. 如果待访问的Data声明了访问需要权限,则访问此Data需在配置文件中声明需要此权限:
    "reqPermissions":
    [
        {
                "name": "com.example.myapplication5.DataAbility.DATA"
        },
        // 还需添加访问存储读写权限
        {
                "name": "ohos.permissions.READ_USER_STORAGE"
        },
        {
                "name": "ohos.permissions.WRITE_USER_STORAGE"
        }
    ]

创建DataAbilityHelper

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

访问Data Ability

客户端访问文件

  • 该方法返回一个目标文件的FD(文件描述符),把文件描述符封装成流,开发者就可以对文件流进行自定义处理
    // 读取文件描述符
    FileDescriptor fd = helper.openFile(uri, "r");
    // 使用文件描述符封装成的文件流进行操作
    FileInputStream fis = new FIleInputStream(fd);

关系型数据库

运作机制

  • HarmonyOS关系型数据库对外提供通用操作接口,底层使用SQLite作为持久化存储引擎,支持SQLite具有的所有数据库特性,包括但不限于事务、索引、视图、触发器、外键、参数化查询和预编译SQL语句

接口说明

类名接口名描述
StoreConfig.Builderpublic builder()对数据库进行配置,包括设置数据库名、存储模式、日志模式、同步模式、是否为只读、数据库加密
RdbOpenCallbackpublic abstract void onCreate(RdbStore store)数据库创建时被回调,开发者可在该方法中初始化表结构,并添加一些应用使用到的初始化数据
RdbOpenCallbackpublic abstract void onUpgrade(RdbStore store, int currentVersion, int targetVersion)数据库升级时被回调
DatabaseHelperpublic RdbStore getRdbStore(StoreConfig config, int versions, RdbOpenCallback opencallback, ResultSetHook resultSetHook)根据配置创建或打开数据库
DatabaseHelperpublic boolean deleteRdbStore(String name)删除指定数据库

新增

  • 关系型数据库提供了插入数据的接口,通过ValuesBucket输入要存储的数据,通过返回值判断是否插入成功,插入成功时返回最新插入数据所在行号,失败返回1类名接口名描述
    RdbStorelong insert(String table, ValuesBucket initialValues)table:待添加数据表名 initialValues:以ValuesBucket存储的待插入的数据。它提供一系列put方法,如putString(String columnName, String values)、putDouble(String columnName, double value),用于向ValuesBucket中添加数据

查询

  • 直接调用查询接口。使用该接口,会将包含查询条件的谓词自动拼接成完整的SQL语句进行查询,无需传入原生SQL
  • 执行原生用于 查询的SQL语句

谓词的使用

  • 关系型数据库提供了用于设置数据库操作条件的谓词AbsRdbPredicates,其中包括两个实现子类RdbPredicatesRawRdbPredicates
    • RdbPredicates:仅通过调用该类中条件相关方法,如equalTo、notEqualTo、groupBy、orderByAsc、beginsWith等,就可自动完成SQL语句拼接
    • RawRdbPredicates:可满足复杂SQL语句场景,支持开发者自己设置where条件子句whereArgs参数,不支持equalTo等条件接口使用

查询结果集的使用

  • 关系型数据库提供了查询返回结果集ResultSet,它指向查询结果中的一行数据,供用户对查询结果遍历和访问

开发步骤

  1. 创建数据库
    • 配置数据库相关信息,包括名称、存储模式、是否为只读模式
    • 初始化数据库表结构和相关数据
    • 创建数据库
StoreConfig config = StoreConfig.newDefaultConfig("RdbStoreTest.db");
private static RdbOpenCallback callback = new RdbOpenCallback()
{
        @Override
        public void onCreate(RdbStore store)
        {
                store.executeSql("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER, salary REAL, blobType BLOB)");
        }
}
@Override
public void onUpgrade(RdbStore store, int oldVersion, int newVersion);
DatabaseHelper helper = new DatabaseHelper(context);
RdbStorestore = helper.getRdbSrore(config, i, callback, null);
  1. 插入数据
    • 构造要插入的数据,以ValuesBucket形式存储
    • 调用关系型数据库提供的插入接口
ValuesBucket values = new ValuesBucket();
values.putInteger("id", 1);
values.putString("name", "zhangsan");
values.putInteger("age", 18);
values.puyDouble("salary, 100.5");
values.putByteArray("blobType", new byte[] {1, 2, 3});
long id = store.insert("test", values);
  1. 查询数据
    • 构造用于查询的谓词对象,设置查询条件
    • 指定查询返回的数据列
    • 调用查询接口查询数据
    • 调用结果集接口,遍历返回结果
String[] columns = new String[] {"id", "name", "age", "salary"};
RdbPredicates rdbPredicates = new RdbPredicates("test").equalTo("age", 25).orderByAsc("salary");
ResultSet resultSet = store.query(rdbPredicates, columns);
resultSet.goToNextRow();

留下评论

您的电子邮箱地址不会被公开。