鸿蒙应用开发实战【87】— 常见崩溃排查null指针与类型断言

鸿蒙应用开发实战【87】--- 常见崩溃排查null指针与类型断言

本文是「号码助手全栈开发系列」第 87 篇,持续更新中...

开源社区:https://openharmonycrossplatform.csdn.net


前言

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 页面销毁后更新 取消待处理异步操作 运行时监控

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

相关推荐
网络豆16 小时前
开源鸿蒙平台 CMP 三方库「navigation-compose-extended」适配全流程
华为·开源·harmonyos
2601_9494800618 小时前
开源鸿蒙平台 CMP 三方库「multiplatform-markdown-renderer」适配全流程
华为·开源·harmonyos
威哥爱编程21 小时前
HarmonyOS 7 Agent 开发实战 10:降级兜底与重试
agent·harmonyos
威哥爱编程21 小时前
HarmonyOS 7 Agent 开发实战 11:并发多会话隔离
agent·harmonyos
威哥爱编程21 小时前
HarmonyOS 7 Agent 开发实战 12:人机协同与人工接管
agent·harmonyos
鸿蒙开发21 小时前
鸿蒙动态表单实战:用 @hmkit/validator 处理条件必填与错误联动
harmonyos
行者-全栈开发21 小时前
【共创稿事节】HarmonyOS 三方库工程化集成:从 ohpm 引入到三方库鸿蒙化的完整闭环
harmonyos·鸿蒙·har·三方库·ohpm·框架适配
网络豆1 天前
开源鸿蒙平台 CMP 三方库「tanstack-table-kmp」适配全流程
华为·开源·harmonyos
贾伟康1 天前
【共创稿事节】食材百科页的懒加载改造:LazyForEach、IDataSource 与缓存窗口的三次迭代
性能优化·harmonyos·arkts·lazyforeach·列表加载
SZYSK1 天前
一套人员主数据,三套事务:通行、消费、人证比对如何分事件类型
物联网·算法·harmonyos