鸿蒙应用开发实战【87】--- 常见崩溃排查null指针与类型断言
本文是「号码助手全栈开发系列」第 87 篇,持续更新中...
前言
ArkTS 严格模式下,空指针和类型断言是运行时崩溃的主要来源。号码助手项目在开发中遇到并解决了多类崩溃问题。本篇整理常见崩溃场景、根因分析和预防措施。
本篇涵盖 :null 指针(
!.与?.选择)、类型断言失败(as风险)、ResultSet 关闭与游标越界、undefined id 导致的数据库更新失败、Promise 未 catch 异常、页面销毁后更新 State 崩溃。

一、null 指针崩溃
1.1 非空断言 ?. vs 强制解包 !.
typescript
// ❌ 危险:如果 card 为 null,直接崩溃
Text(this.card!.phone_number)
// ✅ 安全:使用 ?. 可选链
Text(this.card?.phone_number ?? '')
// ✅ 安全:提前 return
if (!this.card) return
Text(this.card.phone_number) // 此处可安全使用 !
1.2 项目中实际的 null 指针场景
typescript
// CardDetailPage
private async loadData(): Promise<void> {
try {
const card = await CardDao.findById(this.cardId)
if (!card) {
promptAction.showToast({ message: '卡号不存在或已被删除' })
this.getUIContext().getRouter().back() // null 时直接返回
return
}
this.card = card // 此后可安全使用 this.card!
} catch (e) { ... }
}
1.3 undefined id 问题
typescript
// ❌ 危险:entity.id 可能为 undefined
await CardDao.deleteById(this.card!.id!) // 双重非空断言
// ✅ 安全:提前校验
if (!this.card || this.card.id === undefined) return
await CardDao.deleteById(this.card.id)
二、类型断言失败
2.1 as 的风险
typescript
// 数据库中可能存储了非法值
status: rs.getString(rs.getColumnIndex('status')) as BindingStatus
// 如果数据库返回 '未知状态',as 不会阻止崩溃
// 方案:parseRow 中加兜底
const rawStatus = rs.getString(rs.getColumnIndex('status'))
status: ['使用中', '待换绑', '待注销', '已停用'].includes(rawStatus)
? rawStatus as BindingStatus
: '使用中'
三、ResultSet 操作规范
typescript
// ❌ 危险:未检查行数直接读取
const rs = await store.query(predicates, COLS)
const id = rs.getLong(rs.getColumnIndex('id')) // 游标在-1位置
// ✅ 正确:先 goToFirstRow 再读取
rs.goToFirstRow()
const id = rs.getLong(rs.getColumnIndex('id'))
// ✅ 或者检查 rowCount
if (rs.rowCount > 0 && rs.goToFirstRow()) {
// 安全读取
}
rs.close() // 务必关闭
四、页面销毁后更新 State
typescript
// 场景:异步回调在页面已销毁后尝试更新 State
private async doBackup(): Promise<void> {
this.backing = true
try {
// 异步操作
} finally {
// 如果页面已被销毁(用户按了返回),此处崩溃
this.backing = false // 崩溃:Cannot update state after page destroyed
}
}
预防 :在页面生命周期 onPageHide 或 aboutToDisappear 中取消待处理的异步操作。
小结
| 崩溃类型 | 原因 | 预防 | 检测方式 |
|---|---|---|---|
| null 指针 | 对象为 null 时用 ! 解包 |
提前校验 + ?. + ?? 兜底 |
编译时 lint |
| 类型断言 | as 转换不兼容类型 | parseRow 加兜底默认值 | 单元测试 |
| ResultSet | 未 goToFirstRow 直接读取 | 先检查 rowCount 再读取 | Code Review |
| undefined id | 实体可选 id | if (id === undefined) return |
静态分析 |
| 异步 State | 页面销毁后更新 | 取消待处理异步操作 | 运行时监控 |
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- openHarmony 跨平台社区:https://openharmonycrossplatform.csdn.net
- HarmonyOS 官方文档:https://developer.huawei.com/consumer/cn/doc/
- HarmonyOS hilog文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/hilog
- HarmonyOS testing:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/unit-test
- ArkTS 严格模式开发:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-strict-mode