本原创文章帖发布在华为开发者联盟社区,欢迎开发者前往访问评论交流,更多与该内容相关讨论,请点击原帖查看:HarmonyOS开发常见问题及解答(二)-华为开发者话题 | 华为开发者联盟
FAQ 1:HarmonyOS imageSource.getImageProperty 接口内存泄漏问题如何分析?
【解决方案】:
【问题定位】
一、ImageSource/PixelMap 对象未释放:
调用 createPixelMap 后未主动调用 release()释放资源,导致底层共享内存(如/dev/ashmem/EXT RawData)未回收。
多次调用 getImageProperty 可能累积未释放的临时对象。
二、Exif 数据解析残留:
解析大尺寸图片的 Exif 信息时,若未正确处理旋转后的 PixelMap 缓存,可能占用 ION 内存。
三、异步操作未终止:
网络图片下载过程中组件销毁,但异步任务仍持有对 Image 组件的强引用。
【修改建议】
1、显式释放资源
import image from '@kit.ImageKit';async function loadImage() { let imageSource: image.ImageSource | null = null; try { imageSource = image.createImageSource(filePath); const pixelMap = await imageSource.createPixelMap(); // 使用pixelMap后显式释放 pixelMap.release(); } catch (err) { console.error("Error:", err); } finally { // 释放ImageSource imageSource?.release(); }}2、组件生命周期管理
import { image } from '@kit.ImageKit';@Entry@Componentstruct ImageComponent { @State pixelMap: image.PixelMap | null = null; aboutToDisappear() { this.pixelMap?.release(); // 组件销毁前释放资源 } build() { Column() { Image(this.pixelMap) .onClick(async () => { const src = image.createImageSource(networkUrl); this.pixelMap = await src.createPixelMap(); }) } }}3、异步任务管理
import { taskpool } from '@kit.ArkTS';// 使用TaskPool避免持有组件引用taskpool.execute(async () => { const src = image.createImageSource(filePath); const orientation = src.getImageProperty('Orientation'); src.release(); return orientation;});【典型错误场景】:
案例:未关闭文件流导致 ION 泄漏
// 错误示例:未释放ImageSourceimageSource.createPixelMap().then(pixelMap => { this.image = pixelMap;});// 正确修正:在Promise链中释放imageSource.createPixelMap().then(pixelMap => { this.image = pixelMap; imageSource.release(); // 显式释放});FAQ 2:har 文件间相互依赖导致运行时模块导入错误,无法正确使用导出的代码,导致运行崩溃,如何分析?
【解决方案】:
HAR 模块间动态 import 依赖解耦
当应用包含多个 HAR 包,HAR 包之间的依赖关系比较复杂。在 DevEco Studio 中配置依赖关系时,可能会形成循环依赖。这时,如果 HAR 之间的依赖关系中仅有变量动态 import,可以将 HAR 包之间直接依赖关系转移到 HAP/HSP 中配置,HAR 包之间无需配置依赖关系,从而达到 HAR 包间依赖解耦的目的。如下示意图:

HAR 之间的依赖关系转移至 HAP/HSP 后:

使用限制
• 仅限在本地源码 HAR 包之间存在循环依赖时,使用该规避方案。
• 被转移依赖的 HAR 之间只能通过变量动态 import,不能有静态 import 或常量动态 import。
• 转移依赖时,需同时转移 dependencies 和 runtimeOnly 依赖配置。
• HSP 不支持转移依赖。即:HAP->HSP1->HSP2->HSP3,这里的 HSP2 和 HSP3 不能转移到 HAP 上面。
• 转移依赖的整个链路上只能有 HAR 包,不能跨越 HSP 转移。即:HAP->HAR1->HAR2->HSP->HAR3->HAR4,HAR1 对 HAR2 的依赖可以转移到 HAP 上,HAR3 对 HAR4 的依赖可以转移到 HSP 上。但是,不能将 HAR3 或 HAR4 转移到 HAP 上。
• 如果引用了其他工程模块、远程包或集成 HSP,需确保在工程级build-profile.json5文件中的 useNormalizedOHMUrl 配置一致,同时设置为 true 或 false,否则可能导致运行错误:Cannot find dynamic-import module library。
FAQ 3:通过 resourceManager.getStringResource 接口获取 HSP 资源文件报“Resource id invalid”错误 如何解决?
【详细场景】:
通过 this.resourceManager.getStringResource($r('app.string.PlayCount').id)获取 HSP 资源文件时出现错误。
错误消息:资源 ID 无效。
错误代码:9001001
SourceCode:returnResource = this.context.resourceManager.getStringSync(id)。【解决方案】:
根据模块名创建上下文 Context,然后使用 getStringByNameSync 方法获取指定资源名称对应的字符串。具体示例代码如下:
import { common, application } from '@kit.AbilityKit';import { BusinessError } from '@kit.BasicServicesKit';import { JSON } from '@kit.ArkTS'; @Entry@Componentstruct Index { private context = this.getUIContext().getHostContext() as common.UIAbilityContext; build() { Column() { Button() .onClick(() => { // Create a context based on the module name let moduleName: string = 'library'; application.createModuleContext(this.context, moduleName) .then((data: common.Context) => { console.info(`CreateModuleContext success, data: ${JSON.stringify(data)}`); if (data !== null) { this.getUIContext().getPromptAction().showToast({ message: ('get Context success') }); } // Then run getStringByNameSync to obtain the string corresponding to the specified resource name try { let str = data.resourceManager.getStringByNameSync('shared_desc'); console.info(`getStringByNameSync, data: ${JSON.stringify(str)}`); } catch (error) { let code = (error as BusinessError).code; let message = (error as BusinessError).message; console.error(`getStringByNameSync failed, error code: ${code}, message: ${message}.`); } }) .catch((err: BusinessError) => { console.error(`CreateModuleContext failed, err code:${err.code}, err msg: ${err.message}`); }); }) } }}参考链接
应用上下文Context、获取本应用中其他module的context、getStringByNameSync
FAQ 4:对于数据量大的赋值操作造成的卡顿和崩溃,该怎么解决?
【解决方案】:
数据精准懒加载:
当数据源总长度较长,或数据项加载耗时较长时,可使用 Repeat 数据精准懒加载特性,避免在初始化时加载所有数据。Repeat 数据精准懒加载特性从 API version 19 开始支持。
开发者可以设置.virtualScroll()的 totalCount 属性值或 onTotalCount 自定义方法用于计算期望加载的数据项总数,设置 onLazyLoading 属性实现数据精准懒加载,实现在节点首次渲染时加载对应的数据。详细说明和注意事项见VirtualScrollOptions。
示例
数据源总长度较长,在首次渲染、滑动屏幕、跳转显示区域时,动态加载对应区域内的数据。
@Entry@ComponentV2struct RepeatLazyLoadingLongData { // 假设数据源总长度较长,为1000。初始数组未提供数据。 @Local arr: Array<string> = []; scroller: Scroller = new Scroller(); build() { Column({ space: 5 }) { // 初始显示位置为index = 100,数据可通过懒加载自动获取。 List({ scroller: this.scroller, space: 5, initialIndex: 100 }) { Repeat(this.arr) .virtualScroll({ // 期望的数据源总长度为1000。 onTotalCount: () => { return 1000; }, // 实现数据懒加载。 onLazyLoading: (index: number) => { this.arr[index] = index.toString(); } }) .each((obj: RepeatItem<string>) => { ListItem() { Row({ space: 5 }) { Text(`${obj.index}: Item_${obj.item}`) } } .height(50) }) } .height('80%') .border({ width: 1 }) // 显示位置跳转至index = 500,数据可通过懒加载自动获取。 Button('ScrollToIndex 500') .onClick(() => { this.scroller.scrollToIndex(500); }) } }}更多实例及运行效果详见:Repeat:可复用的循环渲染-学习UI范式渲染控制-UI开发 (ArkTS声明式开发范式)-ArkUI(方舟UI框架)-应用框架 - 华为HarmonyOS开发者
FAQ 5:使用向导创建的 worker 线程文件中导出一个 TestThrdMsg 类必现 JSCrash,如何解决?
【解决方案】:
Worker 简介的其它注意事项中有说明:在 Worker 文件中禁止使用 export 语法导出任何内容,否则会导致 jscrash 问题。
使用过程中可参考 Worker 简介:Worker简介-多线程并发-ArkTS并发-ArkTS(方舟编程语言)-应用框架- 华为HarmonyOS开发者
🔗 官网开发者学堂视频:https://developer.huawei.com/consumer/cn/training/result?type2List=201783644516849879&orderBy=1&courseType=5

🔗 社区 DFX 专题文章: https://developer.huawei.com/consumer/cn/forum/subject/2101218731402391001


【扫码加入 HarmonyOS DFX 技术交流群】





