你是不是也在想——“鸿蒙这么火,我能不能学会?”
答案是:当然可以!
这个专栏专为零基础小白设计,不需要编程基础,也不需要懂原理、背术语。我们会用最通俗易懂的语言、最贴近生活的案例,手把手带你从安装开发工具开始,一步步学会开发自己的鸿蒙应用。
不管你是学生、上班族、打算转行,还是单纯对技术感兴趣,只要你愿意花一点时间,就能在这里搞懂鸿蒙开发,并做出属于自己的App!
📌关注本专栏《零基础学鸿蒙开发》,一起变强!
每一节内容我都会持续更新,配图+代码+解释全都有,欢迎点个关注,不走丢,我是小白酷爱学习,我们一起上路 🚀
全文目录:
- 前言
- 一、先说结论:切后台不等于销毁 UIAbility
- 二、HarmonyOS 7 下先把版本和接口确认清楚
- 三、为什么重新进入应用没有重新 onCreate
- 四、搭一个只记录生命周期的最小实验
- 五、按照固定顺序做一次生命周期实验
- 六、锁屏和解锁为什么要单独看
- 七、把生命周期日志整理成一张表
- 八、三个回调分别适合放什么逻辑
- 九、为什么有时重新进入又真的出现 onCreate
- 十、这个实验还有两个容易混淆的点
- 开发经验总结
前言
做 HarmonyOS 应用生命周期相关逻辑时,一个很容易产生的误解是:用户按 Home 键离开应用,之后再从桌面进入应用,看起来像是“重新打开”了一次,那么onCreate()是否也应该重新执行?
在 Stage 模型下,答案取决于UIAbility 实例有没有被重新创建,而不是界面有没有重新出现在用户眼前。
这次只做一个很小的实验:给onCreate()、onForeground()、onBackground()加日志,然后按照“启动 → Home 键 → 再进入 → 锁屏 → 解锁”的顺序观察生命周期。重点不是把所有生命周期接口罗列一遍,而是把“创建实例”和“前后台切换”这两件经常混在一起的事情拆开。
需要先说明:下面代码依据 HarmonyOS 官方接口组织,但本文无法代替目标设备完成真机执行,因此不会把预期日志冒充为已经采集到的真机结果。尤其是锁屏、解锁环节,最终日志应以目标 HarmonyOS 7 设备上的实际输出为准。
一、先说结论:切后台不等于销毁 UIAbility
Stage 模型中的 UIAbility 是包含 UI 的应用组件。官方对 Stage 模型的说明中明确指出,UIAbility 生命周期包含创建、销毁、前台、后台等状态,而窗口显示相关状态由 WindowStage 暴露。
因此,理解这篇文章只需要先分清两组概念:
| 回调 | 它表达的核心含义 |
|---|---|
onCreate() | UIAbility 实例被创建 |
onForeground() | UIAbility 进入前台 |
onBackground() | UIAbility 进入后台 |
onDestroy() | UIAbility 实例被销毁 |
这里真正需要关注的是:Foreground → Background → Foreground 可以发生在同一个 UIAbility 实例上。
按 Home 键通常解决的是“当前 UIAbility 不再处于前台”这个问题,并不等价于调用terminateSelf(),也不能简单理解成“应用已经销毁”。
这也是为什么观察到:
onBackground onForeground却没有第二次onCreate,本身并不矛盾。
官方 Stage 模型还说明,后台应用会受到系统统一的进程管理;当系统资源不足时,后台应用可能被回收。因此,“进入后台后实例暂时仍然存在”和“后台实例永远不会被销毁”同样不是一回事。
二、HarmonyOS 7 下先把版本和接口确认清楚
本文按 HarmonyOS 7 开发背景讨论。华为当前升级适配文档明确给出了 HarmonyOS 7.0 与API version 26.0.0的对应关系,并建议升级到 26.0.0 开发套件后完成兼容性验证。
这里使用的是 Stage 模型下的UIAbility,相关能力属于 Ability Kit。当前官方示例使用统一 Kit 导入方式:
import{AbilityConstant,UIAbility,Want}from'@kit.AbilityKit';生命周期日志则可以通过 Performance Analysis Kit 中的 HiLog 输出。官方资料说明,Performance Analysis Kit 提供 HiLog 流水日志能力,用于记录和获取应用运行日志;当前官方代码示例采用:
import{hilog}from'@kit.PerformanceAnalysisKit';本文只是记录 UIAbility 生命周期,不涉及相机、定位、网络、后台长时任务等能力,因此这个最小实验不需要额外声明运行时权限。
这里也不需要为了观察生命周期额外调用moveAbilityToBackground()。实验要验证的是正常用户操作下的状态变化,直接使用 Home 键即可。
三、为什么重新进入应用没有重新 onCreate
这个问题还需要结合 UIAbility 的启动模式来看。
官方“UIAbility组件启动模式”文档定义了singleton、multiton和specified三种模式,其中singleton是默认启动模式。对于已经存在的 singleton UIAbility,再次启动时系统会复用已有实例,而不是重新创建实例。
这意味着:
第一次创建实例 ↓ onCreate ↓ 进入前台 ↓ onForeground ↓ Home ↓ onBackground ↓ 再次进入 ↓ 复用原来的 UIAbility ↓ onForeground这里没有产生新的 UIAbility 实例,自然没有理由再次执行onCreate()。
这也是生命周期问题里最需要建立的判断方式:
不要根据“用户是不是重新点了应用图标”判断 onCreate,而应该根据“系统是不是重新创建了这个 UIAbility 实例”判断。
另外需要区分一种相近但并不完全相同的情况。官方生命周期规则中,在一个已经存在的 UIAbility 被再次拉起时,某些启动场景还会涉及onNewWant();启动模式文档也明确指出,singleton 实例已经存在时,再次通过启动机制拉起该 UIAbility,不会重新进入onCreate()和onWindowStageCreate()。本文实验只记录三个核心回调,所以不把onNewWant()加进日志,但实际排查“应用图标再次启动”“Want 参数刷新”之类的问题时,需要把它纳入观察范围。
四、搭一个只记录生命周期的最小实验
实验不需要业务页面,也不需要状态管理。保留默认 EntryAbility,在三个生命周期回调里打印统一格式的日志即可。
为了让日志容易过滤,可以固定一个 TAG:
import{AbilityConstant,UIAbility,Want}from'@kit.AbilityKit';import{hilog}from'@kit.PerformanceAnalysisKit';constDOMAIN=0x0000;constTAG='AbilityLifecycle';exportdefaultclassEntryAbilityextendsUIAbility{onCreate(want:Want,launchParam:AbilityConstant.LaunchParam):void{hilog.info(DOMAIN,TAG,'%{public}s','onCreate');}onForeground():void{hilog.info(DOMAIN,TAG,'%{public}s','onForeground');}onBackground():void{hilog.info(DOMAIN,TAG,'%{public}s','onBackground');}}这段代码只解决一件事:给 UIAbility 的创建、进入前台、进入后台三个状态打时间点。
官方现有示例同样通过继承UIAbility,在onCreate()、onForeground()和onBackground()中使用hilog.info()记录生命周期,因此这里没有自行设计新的生命周期接口。
如果是在默认工程中实际复现,不要为了使用上面这段代码把原有的onWindowStageCreate()删除掉。默认页面仍然需要正常创建 WindowStage、调用loadContent()加载 ArkUI 页面;这里只是省略与本次实验无关的窗口代码。
换句话说,实际工程可以保持原来的:
onWindowStageCreate(windowStage:window.WindowStage):void{windowStage.loadContent('pages/Index');}再把三个日志回调加入 EntryAbility。
真正需要观察的不是页面内容,而是 DevEco Studio 的日志窗口。
五、按照固定顺序做一次生命周期实验
操作顺序保持简单:
启动应用 ↓ 按 Home 键 ↓ 重新进入应用 ↓ 锁屏 ↓ 解锁并回到该应用启动阶段最容易判断。新的 UIAbility 实例创建时会进入onCreate();应用进入前台时会进入onForeground()。
因此首次启动时,本文关注的核心日志应包含:
onCreate onForeground这里并不是说完整启动流程只有这两个回调。包含 UI 的 UIAbility 还涉及 WindowStage 生命周期,只是本实验有意把观察范围压缩到了三个回调。
接着按 Home 键。
应用从前台离开后,关注:
onBackground此时最重要的观察点不是“有没有 onBackground”,而是后面重新进入时有没有再次出现onCreate。
如果 UIAbility 实例仍然存在,再次回到前台关注:
onForeground而不是:
onCreate onForeground这正好可以验证本文的问题:前后台切换和实例创建是两条不同的生命周期语义。
六、锁屏和解锁为什么要单独看
锁屏比 Home 键稍微特殊一些,因为它不只是“用户打开了另一个普通应用”,还涉及系统锁屏状态以及后台资源治理。
华为官方关于后台资源和跨设备生命周期管理的资料,都把“锁屏”和“退至后台”作为需要进行后台资源管理的场景。例如官方后台视频导出最佳实践明确说明,普通应用在切到后台、锁屏或熄屏后会受到后台执行限制,需要持续执行特定任务时应使用对应的后台任务机制。
因此,在生命周期实验中,锁屏是很有价值的一步,但这里不应该脱离设备环境硬写一份“所有设备必然完全一致”的日志。
复现时建议这样判断:
如果锁屏导致当前 UIAbility 进入后台,应看到:
onBackground随后解锁,并且系统重新显示的仍然是这个 UIAbility、实例也没有在后台被销毁,那么关注:
onForeground如果后台期间实例已经被系统回收,那么之后重新进入应用就属于新的实例创建过程,此时重新出现onCreate()才是合理现象。
这也是为什么不能把“Home 后没有 onCreate”扩展成“以后永远不会再执行 onCreate”。
七、把生命周期日志整理成一张表
下面这张表更适合作为实验前的预期观察表。实际发布文章时,可以在目标 HarmonyOS 7 真机完成操作后,用设备真实日志替换“预期关注日志”一列。
| 操作 | UIAbility 状态变化 | 预期关注日志 | 是否意味着创建新实例 |
|---|---|---|---|
| 首次启动应用 | 创建 → 前台 | onCreate→onForeground | 是 |
| 按 Home 键 | 前台 → 后台 | onBackground | 否 |
| 再次进入,且原实例仍存在 | 后台 → 前台 | onForeground | 否 |
| 锁屏并使 Ability 进入后台 | 前台 → 后台 | 关注onBackground | 否 |
| 解锁后恢复原 Ability | 后台 → 前台 | 关注onForeground | 否 |
| 后台实例已被系统销毁后再次启动 | 重新创建 → 前台 | 会重新出现onCreate,随后进入前台生命周期 | 是 |
这里最有价值的其实是第二、三行。
用户视觉上的操作是:
离开应用 → 再打开应用而 UIAbility 视角可能只是:
Foreground → Background → Foreground没有发生:
Destroy → Create自然也就不会重新执行onCreate()。
八、三个回调分别适合放什么逻辑
理解日志顺序之后,代码应该放在哪里也会清楚很多。
onCreate()更适合处理和UIAbility 实例创建强绑定的初始化。如果把“每次用户重新看到应用都要执行”的刷新逻辑只放在这里,那么 Home → 再进入时很可能不会重新执行。
onForeground()对应 UIAbility 重新进入前台。官方资源使用示例也采用在onForeground()中申请或恢复前台所需资源、在onBackground()中停止后台不应继续使用的资源这种模式。例如官方传感器资源合理使用示例就在前台注册传感器监听,在onBackground()中取消监听。
onBackground()则适合处理进入后台后的资源释放或业务状态切换。但这不代表任何任务放进onBackground()后都可以无限在后台执行。Stage 模型对后台应用存在系统治理,持续后台运行的业务需要使用系统提供的相应后台机制,而不能把生命周期回调当成“后台保活入口”。
一个比较典型的理解偏差就是:
onCreate():void{// 每次回到应用都刷新数据}代码本身可以写,但注释表达的业务假设并不成立。
如果需求真的是“UIAbility 每次重新进入前台时检查数据是否需要刷新”,判断入口应该优先围绕onForeground()设计,再由业务自己决定是否真正发起刷新,而不是强行要求onCreate()重复执行。
九、为什么有时重新进入又真的出现 onCreate
如果实验中发现第二次进入应用确实打印了onCreate(),也不能立刻认定生命周期异常。
onCreate()的核心判断仍然是:当前是不是创建了新的 UIAbility 实例。
后台应用受到系统资源管理。当后台实例已经被销毁,之后再次启动自然需要创建新的 UIAbility,于是onCreate()会再次出现。
启动模式也会改变实例创建行为。官方文档说明,multiton模式每次启动都可以创建新的该类型 UIAbility 实例;singleton则会在已有实例存在时复用实例。
因此看到onCreate()次数不符合预期时,排查顺序可以压缩成下面这条链路:
确认是不是 Stage 模型 ↓ 确认当前 UIAbility 的 launchType ↓ 确认此前实例是否真的仍然存在 ↓ 确认操作只是前后台切换,还是重新启动了 UIAbility ↓ 再检查 onCreate / onForeground / onBackground 日志不要反过来根据日志数量猜系统行为。
十、这个实验还有两个容易混淆的点
第一个是UIAbility 生命周期和 ArkUI 页面生命周期不是一回事。
onCreate()、onForeground()、onBackground()属于 UIAbility。ArkUI 自定义组件还有自己的创建、显示和销毁相关回调。本文只讨论 UIAbility,不把页面aboutToAppear()等回调混进来,否则“页面出现”和“Ability 进入前台”很容易再次混成同一个概念。
第二个是后台不等于销毁。
Home 键让应用离开前台,并不能作为“所有内存状态已经清空”的依据。如果业务必须跨生命周期保存数据,不能因为一次 Home → 返回实验中实例没有被销毁,就依赖内存变量永久保存重要状态。系统对后台进程有自己的资源管理策略。
开发经验总结
这个最小实验真正要记住的不是某一串日志,而是 UIAbility 生命周期的判断基准。
onCreate()回答的是“这个 UIAbility 实例是不是刚刚创建”;onForeground()回答的是“它是不是进入了前台”;onBackground()回答的是“它是不是离开了前台进入后台”。
所以,应用按 Home 后再进入,没有重新执行onCreate()并不奇怪。只要原 UIAbility 实例仍然存在,前后台切换本来就不需要重新创建实例。
反过来,如果业务希望“用户每次重新回到应用都执行一次检查”,也不要把逻辑全部压在onCreate()。应该先确认真正需要监听的是实例创建,还是 UIAbility 回到前台。
最后还有一个很适合自己继续验证的实验:在当前三个日志之外,再加入onDestroy(),然后分别测试 Home、任务中心划掉应用、系统回收后的再次启动。把“后台”和“销毁”真正拆开以后,很多生命周期问题会变得直观得多。
❤️ 如果本文帮到了你…
- 请点个赞,让我知道你还在坚持阅读技术长文!
- 请收藏本文,因为你以后一定还会用上!
- 如果你在学习过程中遇到bug,请留言,我帮你踩坑!