你是不是也在想——“鸿蒙这么火,我能不能学会?”
答案是:当然可以!
这个专栏专为零基础小白设计,不需要编程基础,也不需要懂原理、背术语。我们会用最通俗易懂的语言、最贴近生活的案例,手把手带你从安装开发工具开始,一步步学会开发自己的鸿蒙应用。
不管你是学生、上班族、打算转行,还是单纯对技术感兴趣,只要你愿意花一点时间,就能在这里搞懂鸿蒙开发,并做出属于自己的App!
📌关注本专栏《零基础学鸿蒙开发》,一起变强!
每一节内容我都会持续更新,配图+代码+解释全都有,欢迎点个关注,不走丢,我是小白酷爱学习,我们一起上路 🚀
全文目录:
- 前言
- 一、onMemoryLevel 解决的不是“查剩余内存”
- 二、先把官方规则和版本变化弄清楚
- 三、搭一个最小实践:把“可重建缓存”分成三层
- 四、在 AbilityStage 中处理内存等级
- 五、别漏掉 module.json5 的 AbilityStage 入口
- 六、哪些缓存适合释放,哪些数据不能跟着清
- 七、还有两个容易误解的地方
- 1. 收到回调,不等于知道自己释放了多少内存
- 2. onMemoryLevel 不是应用内存泄漏的修复器
- 八、实际项目可以按这个顺序排查
- 开发经验总结
前言
应用里的缓存通常是为了用内存换取速度:预取结果、可重新计算的数据、临时索引,都可能长期留在进程里。但系统整体内存开始紧张时,应用如果还按正常状态持有所有非必要资源,就失去了主动收缩的机会。
HarmonyOS 的 Ability Kit 提供了onMemoryLevel()。以AbilityStage为例,当系统决定调整内存时,会把内存压力级别回调给应用,应用可以据此释放不再必要、并且能够重新构建的资源。官方文档明确把AbilityStage、UIAbility和EnvironmentCallback都列为接收内存变化的方式。
这篇文章只做一件事:围绕AbilityStage.onMemoryLevel()搭一个最小实践,把“收到通知之后到底应该清什么、不应该清什么”说明白。
一、onMemoryLevel 解决的不是“查剩余内存”
先把这个接口的定位弄清楚。
onMemoryLevel()不是一个查询“当前还剩多少 MB 内存”的接口。它接收到的是AbilityConstant.MemoryLevel,表达系统当前的内存压力等级。AbilityStage 官方开发指南说明,当系统调整内存时会触发onMemoryLevel(),开发者可以在回调中释放不必要资源。
因此,它更适合解决这样的业务问题:
应用维护了若干用于加速访问的内存缓存。当系统出现内存压力时,根据压力等级逐步丢弃可以重新获得的数据,同时保留用户正在编辑、尚未持久化或业务流程仍然依赖的关键状态。
这里的核心不是“系统帮应用清缓存”,而是系统给出压力信号,具体释放什么仍由应用自己的资源管理策略决定。
这也是为什么onMemoryLevel()最适合与缓存分级一起设计,而不是收到回调之后简单粗暴地执行一次“全清”。
二、先把官方规则和版本变化弄清楚
本文以当前 HarmonyOS 7 开发环境为背景。华为官方的 26.0.0 升级适配说明明确指出,HarmonyOS 7.0 对应 API 26.0.0,并建议开发者基于 26.0.0 开发套件完成升级适配。
AbilityStage 属于 Stage 模型中的模块级组件容器。一个 AbilityStage 实例对应一个模块;默认工程不会自动生成 AbilityStage,需要使用时可以自行创建,并通过module.json5的srcEntry指定入口。官方指南同时明确列出了onMemoryLevel()这个事件回调。
对于本文最关心的三个基础内存等级,华为官方内存分析最佳实践给出的定义如下。需要说明的是,该最佳实践页面目前属于 HarmonyOS 5.0.0(API 12) 的归档文档,因此这里使用它核对三个既有枚举的含义,而不是把该页面当成 HarmonyOS 7 的完整枚举清单。
| MemoryLevel | 值 | 应用侧应理解为什么 |
|---|---|---|
MEMORY_LEVEL_MODERATE | 0 | 系统内存压力适中,系统可能开始按照 LRU 缓存规则处理进程 |
MEMORY_LEVEL_LOW | 1 | 系统内存已经比较低,应释放不必要资源 |
MEMORY_LEVEL_CRITICAL | 2 | 系统内存很低,应尽可能释放不必要资源 |
这里还有一个 HarmonyOS 7 开发时不能忽略的版本点:不要再把MemoryLevel永久写死为“只有 0、1、2 三种值”。官方 6.1.1(24) Beta1 的 Ability Kit API 变更记录已经新增:
MEMORY_LEVEL_UI_HIDDEN = 3、MEMORY_LEVEL_BACKGROUND_MODERATE = 4、MEMORY_LEVEL_BACKGROUND_LOW = 5、MEMORY_LEVEL_BACKGROUND_CRITICAL = 6。
所以,本文虽然围绕题目中的MODERATE / LOW / CRITICAL三档讲最小策略,但面向 API 26 编写代码时,switch最好保留兜底分支,而不是假设枚举永远只有三个成员。
从官方 AbilityStage 示例来看,核心依赖来自 Ability Kit:
import{AbilityStage,AbilityConstant}from'@kit.AbilityKit';本文使用的onMemoryLevel()没有额外申请运行时权限;AbilityStage 的接入重点在 Stage 模型、Ability Kit 以及模块srcEntry配置,而不是权限声明。
三、搭一个最小实践:把“可重建缓存”分成三层
示例不接入图片解码、数据库、网络请求等额外能力,避免把文章变成另一个主题。我们只准备三个Map,模拟三类可以重新获得的数据:
prefetchCache:预取数据,优先级最低;derivedCache:根据原始业务数据计算得到的派生结果,可以再次计算;optionalCache:仍然属于非必要缓存,但正常情况下希望尽量保留。
注意,这三个Map只是为了展示释放策略和代码结构。本文没有测量它们能够释放多少真实内存,也不会据此声称任何具体内存收益。
classDemoMemoryCache{privateprefetchCache:Map<string,string>=newMap();privatederivedCache:Map<string,string>=newMap();privateoptionalCache:Map<string,string>=newMap();releasePrefetchCache():void{this.prefetchCache.clear();}releaseRecreatableCache():void{this.prefetchCache.clear();this.derivedCache.clear();}releaseAllNonEssentialCache():void{this.prefetchCache.clear();this.derivedCache.clear();this.optionalCache.clear();}}exportconstdemoMemoryCache=newDemoMemoryCache();真正迁移到业务工程时,这三个容器可以对应自己的图片内存缓存、预取结果、计算结果或其他可重建对象。关键判断标准不是“它占了多少内存”,而是:
丢掉以后,应用能不能在需要时重新得到它,并且不会造成用户数据丢失。
四、在 AbilityStage 中处理内存等级
AbilityStage 默认不会自动出现在普通工程中。按照官方指南,可以新建例如:
entry/src/main/ets/myabilitystage/MyAbilityStage.ets然后实现onMemoryLevel():
import{AbilityStage,AbilityConstant}from'@kit.AbilityKit';import{demoMemoryCache}from'../common/DemoMemoryCache';exportdefaultclassMyAbilityStageextendsAbilityStage{onMemoryLevel(level:AbilityConstant.MemoryLevel):void{console.info(`onMemoryLevel:${level}`);switch(level){caseAbilityConstant.MemoryLevel.MEMORY_LEVEL_MODERATE:// 压力适中:先放弃低价值的预取缓存demoMemoryCache.releasePrefetchCache();break;caseAbilityConstant.MemoryLevel.MEMORY_LEVEL_LOW:// 内存较低:进一步释放可重新生成的数据demoMemoryCache.releaseRecreatableCache();break;caseAbilityConstant.MemoryLevel.MEMORY_LEVEL_CRITICAL:// 内存非常紧张:释放全部非必要缓存demoMemoryCache.releaseAllNonEssentialCache();break;default:// 新版本可能扩展 MemoryLevel,避免把枚举永久写死为三个值console.info(`Unhandled memory level:${level}`);break;}}}这段代码解决的问题很明确:把系统内存压力和应用自己的缓存回收策略连接起来。
真正需要关注的是三个地方。
第一,不要比较魔法数字0 / 1 / 2,直接使用AbilityConstant.MemoryLevel中的枚举成员。这样代码表达的是“内存压力等级”,而不是几个没有语义的整数。
第二,三个等级不必执行完全相同的操作。如果MODERATE一来就把所有缓存清空,那么分级通知本身的价值就没有发挥出来。可以让释放策略随压力逐步增强。
第三,保留default。官方 API 变更记录已经证明MemoryLevel后续确实发生过扩展。
五、别漏掉 module.json5 的 AbilityStage 入口
如果工程原本没有 AbilityStage,仅仅创建.ets文件还不够。
官方 AbilityStage 指南要求在module.json5中通过srcEntry指定模块入口,例如:
{ "module": { "name": "entry", "type": "entry", "srcEntry": "./ets/myabilitystage/MyAbilityStage.ets" } }实际项目的module.json5通常还有abilities、deviceTypes等其他配置,这里只展示和 AbilityStage 接入直接相关的字段,不建议拿这段最小片段覆盖已有配置。
六、哪些缓存适合释放,哪些数据不能跟着清
onMemoryLevel()最容易出现的理解偏差,是把“释放不必要资源”理解成“清掉当前进程里能找到的所有数据”。
两者完全不是一回事。
比较适合进入内存回收策略的,是能够重新获取、重新加载或重新计算的非必要数据。例如预取结果、派生计算结果,以及应用自己明确设计为可重建的内存缓存。
而下面这类内容不应该仅仅因为收到onMemoryLevel()就直接丢弃:
用户尚未保存的编辑内容、仍在进行中的关键业务状态、唯一存在于内存中且没有其他可靠副本的数据。
可以把判断方式简化成一句话:
Cache 可以考虑释放,Source of Truth 不能被当成 Cache。
比如文章编辑器里已经从服务端加载完成的缩略图缓存,和用户刚刚输入但还没有保存的正文,虽然都可能暂存在内存里,业务意义完全不同。前者丢失后通常可以重新获取,后者如果直接清除就可能造成真实的数据损失。
因此,CRITICAL的含义也不是“允许删除业务数据”,而是应该把非必要资源的释放力度提高。官方对该等级的表述同样限定在“尽可能释放任何不必要的资源”。
七、还有两个容易误解的地方
1. 收到回调,不等于知道自己释放了多少内存
onMemoryLevel(level)给应用的是等级,不是“请释放 120 MB”这样的目标值。
所以不要在文章、日志或性能报告里把“执行了Map.clear()”直接写成“释放了 XX MB”。如果项目需要量化内存变化,应该单独使用内存分析工具建立测试方法,而不是从回调等级推算结果。
华为归档的内存分析最佳实践还给出了通过 HiDumper 查看 PSS,以及使用 DevEco Profiler 进行 Allocation、Snapshot 分析的思路。
2. onMemoryLevel 不是应用内存泄漏的修复器
如果对象仍然被业务代码错误持有,增加一个onMemoryLevel()并不会自动修复引用关系。
这个回调适合做的是主动释放本来就允许释放的资源。内存泄漏、异常对象增长、Native 资源未释放等问题,仍然应该通过对应的内存分析和生命周期管理手段定位。
八、实际项目可以按这个顺序排查
如果已经实现onMemoryLevel(),但发现策略没有达到预期,可以先确认项目是否基于 Stage 模型、AbilityStage 文件是否已经通过module.json5.srcEntry正确注册;再检查回调参数是否使用AbilityConstant.MemoryLevel,而不是自己维护数字常量;然后确认业务真正清理的是可重建缓存,而不是只打印了一条日志;最后再检查代码是否把枚举写死成三个值。
如果项目面向 HarmonyOS 7,还应把 API 26 的版本适配纳入检查范围。官方说明 HarmonyOS 7.0 对应 API 26.0.0;与此同时,MemoryLevel 在更早的 API 24 变更中已经新增了四个枚举成员。也就是说,老文章里“MemoryLevel 就是三档”的写法,已经不能直接当作 HarmonyOS 7 下的完整 API 描述。
这也是这类基础 API 很容易被忽略的一点:接口名字没有变化,不代表枚举和行为边界永远不变。
开发经验总结
onMemoryLevel()本身并不复杂,真正值得设计的是回调之后的资源分级策略。
MODERATE、LOW、CRITICAL可以分别对应逐渐增强的非必要缓存释放力度;真正的业务数据则应该和缓存明确分层,不能因为内存紧张就一起清掉。
在 HarmonyOS 7 / API 26 工程中,还需要注意 MemoryLevel 已经不止早期文档里的三个成员。编写分支时使用官方枚举,并给未来扩展保留兜底,比依赖0 / 1 / 2更稳妥。
最后,不要把“调用了释放代码”和“已经获得某个具体内存收益”画等号。onMemoryLevel()负责提供系统压力信号,实际释放效果仍然需要结合具体资源类型和内存分析工具验证。
如果正在整理项目里的内存缓存,可以先做一个很简单的检查:每个长期驻留内存的对象,能不能明确回答“系统内存紧张时它是否可以丢弃,以及丢弃后从哪里恢复”?能把这个问题回答清楚,onMemoryLevel()才真正有地方落地。
❤️ 如果本文帮到了你…
- 请点个赞,让我知道你还在坚持阅读技术长文!
- 请收藏本文,因为你以后一定还会用上!
- 如果你在学习过程中遇到bug,请留言,我帮你踩坑!