HarmonyOS 7 实战 04:冷启动优化,别让用户干等
白屏两秒,用户以为你卡死了
你有没有遇到过这种情况:点开应用,先白屏一两秒,然后才出现首页。用户不知道发生了什么,只觉得“这 App 好卡”。更糟的是,有些应用启动时还要转圈,转完才显示内容。
冷启动慢,原因通常不是代码写得烂,而是启动阶段做了太多不该做的事。网络请求、数据库初始化、第三方 SDK 注册、大量同步 IO,全堆在 onWindowStageCreate 里,能不慢吗?
这篇就讲清楚 HarmonyOS 7 的冷启动流程,怎么定位耗时点,怎么用 AppStartup 做任务编排,以及那些你天天在犯的启动错误。
一、冷启动到底经历了什么
HarmonyOS 应用的冷启动大致分几个阶段:
-
应用进程创建:系统 fork 出应用进程。
-
AbilityStage 创建:触发
onCreate。 -
UIAbility 创建:触发
onCreate。 -
WindowStage 创建:触发
onWindowStageCreate,加载首页。 -
首页渲染:ArkUI 构建组件树,上屏。
你写的业务代码,主要集中在 2、3、4 三个阶段。如果这些阶段里有耗时操作,启动就会变慢。
先看一个典型的错误写法:
typescript
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
// 错误:在 onCreate 里做网络请求
fetchUserInfo();
// 错误:同步读文件
const config = fs.readTextSync('/data/config.json');
// 错误:初始化第三方 SDK
initAnalytics();
}
onWindowStageCreate(windowStage) {
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
console.error('加载首页失败');
}
});
}
}
这些操作每一个都可能花几十到几百毫秒,加起来启动不慢才怪。
二、用埋点找出真正的耗时点
优化之前,先别猜。用 hiTraceMeter 或者简单的 Date.now() 打点,看看每个阶段花了多久。
typescript
import hiTraceMeter from '@ohos.hiTraceMeter';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
hiTraceMeter.startTrace('ability_onCreate', 1);
// 业务逻辑
hiTraceMeter.finishTrace('ability_onCreate', 1);
}
onWindowStageCreate(windowStage) {
hiTraceMeter.startTrace('windowStage_create', 1);
windowStage.loadContent('pages/Index', (err) => {
hiTraceMeter.finishTrace('windowStage_create', 1);
});
}
}
跑几次,在 DevEco 的 Profiler 里看时间线。你会发现,真正耗时的往往不是框架本身,而是你自己加的初始化逻辑。
三、AppStartup:把启动任务管起来
HarmonyOS 提供了 AppStartup 机制,可以把启动任务拆成一个个 StartupTask,按依赖关系自动编排,还能控制是否在启动阶段执行。
先定义一个启动任务:
typescript
import { StartupTask, StartupTaskContext } from '@ohos.app.appstartup';
export default class InitAnalyticsTask extends StartupTask {
async init(context: StartupTaskContext): Promise<void> {
// 初始化埋点 SDK
await initAnalytics();
}
}
然后在 module.json5 里配置:
json
{
"module": {
"appStartup": {
"startupTasks": [
{
"name": "InitAnalyticsTask",
"srcEntry": "./ets/startup/InitAnalyticsTask.ets"
}
]
}
}
}
AppStartup 的好处是:任务可以并行、可以设置依赖、可以延迟执行。比如你把非首屏必需的初始化都标记为 isOnDemand: true,等首页显示完再执行。
typescript
export default class InitAnalyticsTask extends StartupTask {
isOnDemand: boolean = true; // 按需执行
async init(context: StartupTaskContext): Promise<void> {
await initAnalytics();
}
}
这样启动阶段只做最关键的事,其他统统往后放。
四、首页渲染优化:别在 build 里做重活
首页本身也要注意。很多人喜欢在 aboutToAppear 里发网络请求,请求回来之前页面是空的,用户看到的就是白屏。
更好的做法是:先渲染骨架屏,数据到了再替换。
typescript
@Entry
@Component
struct Index {
@State data: string[] = [];
@State isLoading: boolean = true;
aboutToAppear() {
this.loadData();
}
async loadData() {
this.isLoading = true;
try {
const result = await fetchData();
this.data = result;
} finally {
this.isLoading = false;
}
}
build() {
Column() {
if (this.isLoading) {
SkeletonList() // 骨架屏组件
} else {
List() {
ForEach(this.data, (item: string) => {
ListItem() {
Text(item)
}
})
}
}
}
}
}
骨架屏不用等数据,立刻就能渲染,用户感知上快很多。等数据回来再替换,体验会好很多。
另外,build() 里别做复杂计算。ArkUI 的 build 会频繁执行,你在里面写个循环排序,页面就卡了。所有计算提前在 aboutToAppear 或 onPageShow 里做完。
五、那些年我们踩过的启动坑
坑一:在 onCreate 里同步读文件。
fs.readTextSync 是同步的,文件稍微大一点就阻塞主线程。改成异步:
typescript
const config = await fs.readText('/data/config.json');
坑二:启动时注册大量监听器。
比如网络状态监听、位置监听、传感器监听,这些注册本身不慢,但回调可能频繁触发,影响启动。非必要的监听,等首页显示完再注册。
坑三:第三方 SDK 初始化太重。
很多 SDK 的 init 方法内部会做网络请求、读文件、开线程。如果它不是首屏必需的,用 AppStartup 的 isOnDemand 延迟加载。
坑四:console.log 打太多。
开发阶段随便打,生产环境一定要关掉。大量日志输出会拖慢启动,尤其是循环里打日志。
六、总结
这篇讲了 HarmonyOS 7 冷启动的流程、定位方法和优化手段。核心记住三点:
-
启动阶段只做最关键的事,其他交给 AppStartup 延迟执行。
-
首页先渲染骨架屏,别让用户干等白屏。
-
用埋点找耗时点,别凭感觉优化。
更多推荐



所有评论(0)