从SwiftData到鸿蒙relationalStore:移植一款精力管理App的三周踩坑记

HarmonyOS 应用开发之ArkData ArkData (方舟数据管理)为开发者提供数据存储、数据管理和数据同步能力,比如联系人应用数据可以保存到数据库中,提供数据库的安全、可靠以及共享访问等管理机制,也支持与手表同步联系人信息。标准化数据定义:提供OpenHarmony跨应用、跨设备的统一数据类型标准,包含标准化数据类型和标准化数据结构。数据存储:提供通用数据持久化能力,根据数据特点,分为用户首选项、键值型数据库和关系型数据库。数据管理:提供高效的数据管理能力,包括权限管理、数据备份恢复、数据共享框架等。 阅读详情

背景:一个用"电量"追踪精力的工具

去年做了个 iOS App 叫「元気手账」,核心想法很简单——把自己当成一块电池,每天起始 50% 电量,做了什么事就加减对应的值。比如"-20 开会消耗"、“+15 散步充电”,一天下来精力流向一目了然。

iOS 版用 SwiftData 搞定数据层,写起来很舒服。年初决定出鸿蒙版,用 ArkTS + ArkUI 重写,整个迁移花了三周。这篇主要聊技术迁移过程中踩的坑。

数据模型迁移:从 SwiftData 到 relationalStore

iOS 版的数据模型靠 @Model 宏自动生成 schema,关系用 @Relationship 声明,SwiftData 帮你处理建表、迁移、自动保存。

到鸿蒙这边,@ohos.data.relationalStore 是标准的关系型数据库 API,要自己写建表 SQL、手动管事务。说白了就是从"ORM 全自动"退回到"手写 SQL + 薄封装"。

核心三张表:

  • daily_baseline:每天起始电量(默认50)
    • energy_record:精力变化记录,带正负 delta
    • project:方舟项目,归类精力投向
      我封装了一个 Repository 层来统一管理读写:
class EnergyRepository {
  private store: relationalStore.RdbStore
  async insertRecord(record: EnergyRecord): Promise<void> {
      const bucket: relationalStore.ValuesBucket = {
            'id': record.id,
                  'title': record.title,
                        'delta': record.delta,
                              'timestamp': record.timestamp,
                                    'projectId': record.projectId ?? '',
                                          'isDeleted': 0
                                              }
                                                  await this.store.insert('energy_record', bucket)
                                                    }
  async getDayRecords(dayStart: number, dayEnd: number): Promise<EnergyRecord[]> {
      const predicates = new relationalStore.RdbPredicates('energy_record')
          predicates.between('timestamp', dayStart, dayEnd)
                .equalTo('isDeleted', 0)
                      .orderByAsc('timestamp')
                          const result = await this.store.query(predicates)
                              return this.parseResultSet(result)
                                }
                                }
                                ```
iOS 版里 SwiftData 的自动保存、懒加载、变更追踪这些能力全没了,每个操作都得自己写。但好处是掌控感更强,出问题知道去哪查。

## 最恶心的坑:时区与自然日判断

每天的基准电量需要判断"今天是否已经创建过 baseline"。iOS 版一行代码:

```swift
Calendar.current.startOfDay(for: Date())

鸿蒙这边没有直接等价的 API。我最开始用 new Date() 然后 setHours(0,0,0,0) 来算自然日起始,看起来没问题——直到测试发现凌晨 0:30 的记录被归到了前一天。

问题出在 Date 对象默认 UTC,而 setHours 操作的是本地时间但时间戳比较用的是 UTC 毫秒数。最后的解法:

function getDayStartTimestamp(): number {
  const now = new Date()
    const offsetMs = now.getTimezoneOffset() * 60 * 1000
      // 当前本地时间对应的UTC毫秒数,减去当天已过的本地毫秒数
        const localMs = now.getTime() - offsetMs
          const localDayStart = localMs - (localMs % (24 * 60 * 60 * 1000))
            return localDayStart + offsetMs
            }
            ```
说实话这段代码我调了两天,在 UTC+8 和 UTC+5:30(印度时区)下反复验证才确认没问题。教训就是:涉及"自然日"的逻辑,一定要显式处理时区偏移,别信默认行为。

## 快捷动作条:降低记录门槛

做记录工具最怕的事:用户懒得打开。

iOS 版我试过三种交互方案,最后胜出的是底部快捷动作条——预设好常用的记录("-20 开会"、"+10 午休"),一次点击完成,不用填表单。

鸿蒙版用 ArkUI 的横向滚动实现:

```arkts
@Component
struct QuickActionStrip {
  @State actions: QuickAction[] = []
  build() {
      Scroll() {
            Row({ space: 12 }) {
                    ForEach(this.actions, (item: QuickAction) => {
                              Button(item.title)
                                          .fontSize(14)
                                                      .borderRadius(16)
                                                                  .backgroundColor(item.delta > 0 ? '#E8F5E9' : '#FBE9E7')
                                                                              .onClick(() => this.commitRecord(item))
                                                                                      })
                                                                                            }.padding({ left: 16, right: 16 })
                                                                                                }
                                                                                                    .scrollable(ScrollDirection.Horizontal)
                                                                                                        .scrollBar(BarState.Off)
                                                                                                          }
                                                                                                          }
                                                                                                          ```
这个交互在鸿蒙上表现挺好,滚动流畅度和 iOS 基本一致。

## 方舟项目:发现精力黑洞

每条记录可以关联一个"方舟项目"——比如写代码、开会、运动。这样按项目维度聚合后就能看出哪件事最耗精力。

我自己用了六周,大概记了 200 多条数据,发现一个反直觉的结论:写技术博客对我是充电行为(平均 +12),而改遗留 bug 才是真正的电量黑洞(平均 -25)。

之前我一直觉得写文章很累,所以总往后排。但数据告诉我它其实是恢复精力的方式。知道这个之后我把改 bug 挪到上午,下午留给写作,整体状态确实好了不少。

项目还有个经验值系统,投入越多等级越高,满级变"传奇"。有点游戏化,但对坚持记录确实有用。

## RDB 批量写入的性能问题

有一天我导入历史数据(大概 80 条),发现明显卡顿。排查后发现是每条 insert 都触发了一次磁盘写入。

解法是用事务包裹批量操作:

```arkts
async batchInsert(records: EnergyRecord[]): Promise<void> {
  await this.store.beginTransaction()
    try {
        for (const record of records) {
              const bucket = this.toBucket(record)
                    await this.store.insert('energy_record', bucket)
                        }
                            await this.store.commit()
                              } catch (e) {
                                  await this.store.rollBack()
                                      throw e
                                        }
                                        }
                                        ```
事务包裹后 80 条记录从 2 秒降到了 200ms 左右。这个优化在 SQLite 系的数据库上是常识,但如果你从 SwiftData 过来可能不会第一时间想到——因为 SwiftData 默认就是批量提交的。

## 折叠屏适配

iOS 版对 iPad 做了最大宽度 700pt 居中显示(用 ViewModifier 实现)。鸿蒙折叠屏也需要类似处理,我用 MediaQuery 监听屏幕宽度断点,大于 600vp 时内容区加 `constraintSize({ maxWidth: 600 })`。

这块倒没什么坑,HarmonyOS 的响应式布局文档写得还算清楚。

## 当前状态

元気手账鸿蒙版 1.2.0 已上架华为应用市场,纯本地存储,不联网不注册。下载量还很少,冷启动期。

接下来计划做元服务卡片(桌面直接显示今日剩余电量),以及用 Canvas 组件画周/月精力趋势曲线。

---

有个问题想请教做过鸿蒙本地数据库的同行:relationalStore 在频繁小量写入的场景下(比如用户一天记录 10-15 次,每次单条 insert),你们有观察到明显的 I/O 性能波动吗?我目前单条写入控制在 50ms 内,但不确定数据量上千之后查询性能会不会劣化。
鸿蒙第16篇——数据持久化 本文介绍的数据持久化是指鸿蒙应用的数据持久化存储。它是将内存中的数据通过文件或数据库的形式保存到设备存储中。鸿蒙支持多种数据存储方式, 包括用户首选项Preferences、 键值型数据库KV-Store和关系型数据库。 阅读详情

相关推荐

从RADIUS服务器到AP:实战搭建一个小型WPA2-Enterprise测试环境(FreeRADIUS + 家用路由器)

本文详细介绍了如何从零搭建WPA2-Enterprise测试环境,使用FreeRADIUS服务器和家用路由器实现企业级WiFi认证。通过实战指南,包括证书生成、EAP-PEAP配置、OpenWrt路由器设置及故障排查,帮助网络工程师和爱好者掌握802.1X协议栈的实际应用。

weixin_28715953的博客 324

关系型数据库的创建

关系型数据库(Relational Database,RDB)是一种基于关系模型来管理数据的数据库。关系型数据库基于SQLite组件提供了一套完整的对本地数据库进行管理的机制,对外提供了一系列的增、删、改、查等接口,也可以直接运行用户输入的SQL语句来满足复杂的场景需要。不支持Worker线程。ArkTS侧支持的基本数据类型:number、string、二进制类型数据、boolean。为保证插入并读取数据成功,建议一条数据不要超过2M。超出该大小,插入成功,读取失败。RdbStore。

m0_63958973的博客 1066

利用 Docker Distribution 搭建私有的 Docker Registry

1、拓扑

weixin_44983653的博客 1067

鸿蒙垃圾分类查询 App 开发实战 — HarmonyOS ArkTS 从零到一

垃圾分类查询App开发摘要 本文介绍使用HarmonyOS ArkTS开发一款垃圾分类查询App的全过程。该App可通过输入物品名称快速查询其所属垃圾分类(可回收物/厨余垃圾/有害垃圾/其他垃圾),并提供热门标签快捷查询和分类统计功能。 技术实现要点 核心技术选型: 采用HarmonyOS ArkTS(Stage模型)开发 使用@kit.ArkData.relationalStore轻量关系型数据库存储150+常见物品分类数据 核心功能: 物品名称模糊搜索 分类结果展示(含颜色标识) 分类统计图表展示 架构

m0_67000457的博客 567

批量读取_MCGS触摸屏如何实现批量读取modbus数据的方法?

前两天,在一个QQ群里,有同行的朋友问,在MCGS中如何实现批量读取数据,因为他当时面临设备,通讯协议才是MODBUS RTU,同时厂家说地址不能分开读,必须是连续的。鉴于他提供的消息是能够设置的地方都试过了。为此,我直接告诉通过脚本,批量读取的方案。那么这个方案究竟如何实现?且看我下面慢慢道来。一、工具1.modsim:仿真PLC或者第三方设备。2.MCGS组态软件3.串口软件:在电脑中生成两不...

weixin_32511509的博客 8159

AIDD机器学习深度学习药物发现与设计教程总结

AIDD(AI Drug Discovery & Design):是近年来非常火热的技术应用,且已经介入到新药设计到研发的大部分环节当中,为新药发现与开发带来了极大的助力。倾向于机器对数据库信息的自我学习,可以对数据进行提取和学习,一定程度上避免了化合物设计过程中的试错路径,同时还会带来很多全新的结构,为药物发现打破常规的结构壁垒。覆盖了机器学习和深度学习,能与新药研发相结合并实质性的应用到靶点预测、高通量筛选、药物设计、药物的ADMET性质预测等;且算力方面,由早期应用于药物发现领域的决策树、随机

wutianlin0723的博客 6814

鸿蒙新特性:Preferences 数据持久化实战 — 构建自动保存草稿箱的完整方案

本文介绍了如何在HarmonyOS应用中使用Preferences API实现草稿箱功能,主要涵盖以下内容: Preferences API概述: 轻量级键值对存储方案,适合保存小型结构化数据 支持同步/异步操作,数据类型包括基本类型和简单对象 草稿箱核心功能设计: 多草稿管理、自动保存(2秒防抖)、跨会话持久化 数据模型采用DraftItem类,包含标题、内容和时间戳 关键技术实现: 使用JSON序列化存储复杂对象 在aboutToAppear生命周期初始化Preferences 实现数据加载、自动保存和

2501_94186029的博客 146

AUTOSAR网络管理配置详解:Vector DaVinci工具全面讲解

手把手带你用Vector DaVinci完成AUTOSAR网络管理模块的配置,涵盖NmChannel、NmPdu、重复帧抑制等关键参数设置,深入解析CAN总线上的NM报文调度与唤醒机制,助你扎实掌握AUTOSAR网络管理核心实践。

weixin_42504649的博客 168

[鸿蒙开发] HarmonyOS应用中如何实现数据持久化存储

用户首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。其会将数据缓存放在内存中,当用户读取的时候,能够从内存中快速获取数据,当需要持久化的时候可以使用flush接口将内存中的数据写入持久化文件中。为了提升数据读写效率,用户首选项会将所有数据存到内存,随着数据量越多,会导致应用占用的内存越大,因此不适合存放过多的数据,适用的场景一般为应用保存用户的个性化设置等。

yihanss的博客 5852

【Arduino 动手做】六舵机自平衡 Rotary Stewart 平台

《Arduino六舵机自平衡Rotary Stewart平台项目》 该项目展示了一个基于Arduino的六自由度Rotary Stewart平台,通过六个舵机实现动态平衡控制。设计采用激光切割框架和TAMIYA 70171套件,提供详细组装指南和开源固件(GitHub可获取)。开发者丹·罗耶分享了3D打印文件、视频演示及运动学优化需求,强调该平台可扩展应用于游戏控制(如Kerbal Space Program)或教育领域。项目链接包含完整资源包,鼓励用户参与改进并分享创作成果。该案例体现了Arduino在机

雕爷学编程 1088

QML教程04 - Image:搞定界面上的所有图片

本文是QML教程系列的第四篇,重点讲解Image控件的实战用法。文章从图片显示常见的变形、卡顿等问题入手,详细介绍了Image的核心属性和使用技巧。主要内容包括:图片路径的三种写法(相对路径、qrc资源、网络URL)、最重要的fillMode属性解析(PreserveAspectFit、PreserveAspectCrop、Stretch的适用场景)、性能优化方法(sourceSize设置)、异步加载(asynchronous)以及圆形头像的实现方案。

BenBierBa的博客 1608

HarmonyOS 应用开发之ArkData_鸿蒙os kv-store

4.鸿蒙开发系统底层方向。1.项目开发必备面试题。5.鸿蒙音视频开发方向。6.鸿蒙车载开发方向。7.鸿蒙南向开发方向。

2401_84181975的博客 1201

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

鸿蒙原生ArkTS通讯录管家实战开发详解

文章摘要: 《鸿蒙原生ArkTS通讯录管家实战开发详解》介绍了一款基于鸿蒙系统的轻量级通讯录管理应用。项目采用ArkTS语言开发,实现了联系人增删改查、分组管理、生日提醒等完整功能。技术亮点包括:利用关系型数据库实现本地持久化、声明式UI响应式特性、全局Builder函数设计模式等。应用采用三层架构设计,包含数据层、业务层和UI层,核心代码集中在单个文件中便于维护。文章详细解析了数据模型设计、配色系统、数据库操作等关键技术点,特别介绍了联系人卡片侧滑操作、表单实时校验等交互细节。该项目既适合普通用户作为通讯

s1316339343的博客 389

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Harmonyos Framework:ArkData

无论是在多设备数据管理、实时数据同步,还是数据的加密与备份,ArkData 都提供了强有力的支持,帮助开发者提升应用的数据处理能力,并确保数据的安全与一致性。对于需要在多个终端间共享数据的应用,如跨平台办公软件、智能家居控制系统等,ArkData 提供了强大的数据同步和管理能力,确保不同终端的数据保持一致,避免数据孤岛的出现。允许应用将对象数据存储在多个设备中,支持跨设备的数据访问和同步。提供对上述模块的数据同步和共享能力,包括支持关系型数据库和键值型数据库的跨设备同步,以及跨应用数据的静默访问能力。

kami806783412的博客 823

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

【中工开发者】——用户管理

在本学期的鸿蒙开发课程中,我们学习了鸿蒙操作系统的基本概念、开发框架以及如何利用鸿蒙的分布式技。为了检验自己所学的知识,我决定完善一下上课讲的用户管理项目,使它能够根据不同的条件进行查询,并且能够指定修改用户信息、删除信息。该项目实现了一个基于 **ArkTS(ArkUI 框架)** 的用户管理 API,用于操作用户数据表的增删改查功能。以下是项目的详细介绍:语言:ArkTS框架:HarmonyOS ArkUI。

qq_75244466的博客 546

arkTs学习数据持久化学习记录

对于数据操作性能来说,效率最高的是用户首选项,所有数据都在内存中。内存的加载或者空间浪费更多kv键值型数据库可以实现各种数据的存储,存取非常方便,而且直接存到硬盘。不用担心数据丢失。但是遇到复杂数据操作的时候,步骤会非常繁琐,例如对数组的增删改查关系型数据库时最强大的一种存储方式,数据量理论上没有限制。对数据库的操作也更加方便,数据更新修改等等,但是需要了解一点关系型数据库概念。和sql语句概念。

Andrew_gz的博客 820

ArkTS与鸿蒙应用开发(5)

在HarmonyOS健康应用开发中,我们特别注重错误处理和用户体验优化,以提供更加稳定和友好的应用体验。

2403_89383749的博客 214

HarmonyOS 关系型数据库 RDB 数据持久化(ArkTS)实战:建库建表、CRUD、事务、FTS、性能优化,一篇搞懂

HarmonyOS RDB数据库实战指南 本文详细介绍了HarmonyOS关系型数据库(RDB)的核心使用方法和最佳实践。主要内容包括: 适用场景:RDB适合结构化数据存储,如学生信息、订单等需要复杂查询的场景 核心概念: 谓词(RdbPredicates):用于条件查询 结果集(ResultSet):游标式数据访问机制 关键约束: 单次查询不超过5000条 同一时间只能一个写操作 单条数据不超过2MB 实战案例: 学生信息表设计 推荐项目结构:RdbManager单例+DAO层 完整CRUD操作实现 事务

Yihong1833100198的博客 1466

HarmonyOS 5.0 自定义组件与状态管理实战:用 RelationalStore 构建可复用的任务看板

做过一段时间鸿蒙开发之后,大部分人都会碰到同一个问题:页面越写越长,逻辑越堆越乱,同样的 UI 在不同页面复制了一遍又一遍。这篇文章想解决的就是这件事。怎么封装真正可复用的自定义组件、组件之间的状态怎么管理、数据怎么用 RelationalStore 存到本地数据库。为什么选 RelationalStore 而不是上一篇用的 Preferences?因为任务看板需要按状态筛选、按时间排序、支持更新操作,这些场景用键值对存储会很别扭,而关系型数据库处理起来很自然。

程序猿追的博客 492

鸿蒙新特性:@ohos.data.relationalStore 本地关系型数据库实战 — 构建图书管理系统

HarmonyOS关系型数据库relationalStore核心API解析 本文深入探讨了HarmonyOS中的关系型数据库解决方案@ohos.data.relationalStore。主要内容包括: 定位与优势:作为本地单设备结构化数据存储方案,相比键值存储更适合图书管理等结构化数据场景,提供强大的SQL查询能力。 核心API详解: 使用getRdbStore()创建/打开数据库,支持四种安全级别配置 通过executeSql()执行DDL语句创建表结构 使用insert()+ValuesBucket安全

2501_94186029的博客 437

HarmonyOS 通讯录管家 —— 基于 ArkTS + SQLite 的联系人管理应用

这是一个基于HarmonyOS ArkTS开发的完整通讯录管理应用,主要特点包括: 技术架构:采用纯ArkTS原生开发,使用SQLite进行本地数据存储,遵循三层架构设计(数据类型层-数据库操作层-UI展示层) 核心功能: 联系人CRUD操作(增删改查) 分组管理(预设5个分组) 模糊搜索(支持姓名/电话搜索) 生日智能提醒(自动计算7天内过生日的联系人) 快速拨号(集成系统拨号功能) 表单验证(各项输入校验) 数据库设计:包含contact(联系人)和contact_group(分组)两个表,支持安全存储

2501_90457493的博客 424

鸿蒙开发实战:SQLite 数据库的本地存储与高效管理

本文详细介绍了在鸿蒙应用开发中,如何使用SQLite数据库进行本地存储与高效管理。通过实战案例,从数据库初始化、表结构设计到核心的增删改查操作,系统讲解了鸿蒙官方推荐的@ohos.data.relationalStore API的使用方法,并分享了事务处理、性能优化等进阶技巧,帮助开发者构建稳定可靠的本地数据存储方案。

o0p1q2r3的博客 469

毕设鸿蒙:从零构建一个符合工程规范的 OpenHarmony 应用

最近在帮学弟学妹看鸿蒙(OpenHarmony)的毕业设计项目,发现一个挺普遍的现象:大家热情很高,但项目跑起来后,代码结构往往一言难尽,像是“能跑就行”的临时拼凑体。环境配置报错、页面逻辑全堆在一个文件里、数据存得乱七八糟……这些问题不仅开发时痛苦,答辩时被老师追问细节也容易露怯。其实,用 OpenHarmony 做毕设,技术上完全能做出工程规范清晰、可维护性强的作品。关键是要在一开始就建立正确的“工程观”,避开那些新手常踩的坑。

2600_94959843的博客 214

我把 iOS 存钱 App 移植到鸿蒙:number 精度丢失坑了我两天

我评估了一下大概要额外两三周,效果还不一定好。结果当我造了 50 个 Goal、每个 Goal 挂 30 条 Transaction 的测试数据后,读取一次全量数据要将近 800ms,而且按状态筛选、按时间排序这种需求得全部读进内存再手动过滤,写起来又丑又慢。去年陆续有用户问鸿蒙能不能用,我看了看 HarmonyOS NEXT 的应用数量,存钱工具类几乎是空白,就动手做了。iOS 可以直接发本地通知,鸿蒙需要先创建 NotificationSlot,不创建就静默失败,连报错都不给你,排查了一会儿才意识到。

same4869的博客 192

沙箱机制:理解鸿蒙应用的文件访问权限与目录结构(15)

严禁硬编码路径与字段:无论是获取沙箱目录还是声明权限,必须使用系统提供的ContextAPI 和标准字段名(如),避免因系统升级导致兼容性问题。严格的资源闭环:网络请求的、数据库查询的ResultSet、文件操作的File/fd均具有严格的资源限制。务必在finally块中执行销毁或关闭操作。敏感数据隔离:密码、Token 等核心敏感数据绝不能存放在公共的 Download 目录,应加密后存入私有沙箱的 EL2 或 EL4 目录下。异步与并发控制:网络请求与数据库操作均为异步操作,推荐使用。

Davina_yu的博客 318
上一篇: 我用 ArkTS 写了个「吃什么」决策工具,聊聊鸿蒙开发中几个有意思的实现细节
下一篇: 独立开发记录:我怎么把一个专注计时器做成了「声音护照」— iOS端技术拆解
SameX-4869
博客等级 码龄17年 3354粉丝 657原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值