前言:理解生命周期是开发的基础
很多新手刚学鸿蒙,上来就写UI和业务逻辑,结果遇到各种莫名其妙的bug:
- 页面跳转后数据丢失了
- 退出页面后音乐还在播放
- 切回应用后状态不对
- 应用在后台运行时耗电严重
这些问题90%都是因为没有正确理解和使用生命周期导致的。
生命周期就像是应用和页面的"人生轨迹",从创建到销毁,每个阶段都会触发对应的回调方法。只有掌握了这些回调的调用时机和作用,你才能写出健壮、高效的鸿蒙应用。
这篇文章我会用最直白的语言,带你搞懂鸿蒙的应用生命周期和页面生命周期,然后教你如何进行页面跳转和数据传递,最后通过一个完整的实战,把这些知识点融会贯通。
一、应用生命周期
应用生命周期指的是整个应用从启动到退出的整个过程。HarmonyOS NEXT中,应用的生命周期由AbilityStage类管理。
1.1 应用的四个生命周期阶段
| 阶段 | 回调方法 | 调用时机 | 主要作用 |
|---|---|---|---|
| 创建 | onCreate() | 应用首次启动时调用,整个应用生命周期只调用一次 | 初始化全局资源、配置全局变量、注册全局事件 |
| 前台 | onForeground() | 应用从后台切换到前台时调用 | 恢复应用状态、重新获取焦点、继续播放音乐 |
| 后台 | onBackground() | 应用从前台切换到后台时调用 | 保存应用状态、暂停不必要的操作、释放部分资源 |
| 销毁 | onDestroy() | 应用完全退出时调用 | 释放所有全局资源、取消所有网络请求、保存最终数据 |
1.2 代码示例
在entry/src/main/ets/entryability/EntryAbility.ets文件中,你可以重写这些生命周期方法:
typescript
import AbilityStage from '@ohos.app.ability.AbilityStage';
import hilog from '@ohos.hilog';
const TAG: string = 'MyApplication';
const DOMAIN: number = 0x0000;
export default class EntryAbility extends AbilityStage {
// 应用创建时调用
onCreate() {
hilog.info(DOMAIN, TAG, '应用创建了');
// 初始化全局配置
// 初始化数据库
// 注册全局事件监听
}
// 应用进入前台时调用
onForeground() {
hilog.info(DOMAIN, TAG, '应用进入前台了');
// 恢复应用状态
// 继续播放音乐
}
// 应用进入后台时调用
onBackground() {
hilog.info(DOMAIN, TAG, '应用进入后台了');
// 保存应用状态
// 暂停音乐播放
// 停止定位等耗电操作
}
// 应用销毁时调用
onDestroy() {
hilog.info(DOMAIN, TAG, '应用销毁了');
// 释放所有全局资源
// 取消所有网络请求
// 注销全局事件监听
}
}
重要提醒:
onCreate()只在应用首次启动时调用一次,应用在后台被杀死后重新启动也会再次调用- 不要在
onBackground()中做耗时操作,系统会限制应用在后台的运行时间 - 一定要在
onDestroy()中释放所有资源,否则会导致内存泄漏
二、页面生命周期
页面生命周期指的是单个页面从创建到销毁的整个过程。这是我们平时开发中接触最多的部分。
2.1 页面的四个核心生命周期回调
| 回调方法 | 调用时机 | 主要作用 |
|---|---|---|
| aboutToAppear() | 页面即将显示时调用,在build()方法之前 | 加载页面数据、初始化页面状态、注册页面事件 |
| onPageShow() | 页面完全显示时调用 | 开始动画、开始播放视频、获取焦点 |
| onPageHide() | 页面被隐藏时调用(比如跳转到新页面或应用进入后台) | 暂停动画、暂停视频播放、保存页面临时状态 |
| aboutToDisappear() | 页面即将销毁时调用 | 释放页面资源、取消网络请求、注销页面事件 |
2.2 生命周期调用顺序演示
我们写一个简单的页面,在所有生命周期方法中添加日志,看看它们的调用顺序:
typescript
@Entry
@Component
struct LifeCycleDemo {
build() {
Column() {
Text("生命周期演示页面")
.fontSize(24)
.margin(20);
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center);
}
// 页面即将显示
aboutToAppear() {
console.log("页面即将显示:aboutToAppear");
}
// 页面完全显示
onPageShow() {
console.log("页面完全显示:onPageShow");
}
// 页面被隐藏
onPageHide() {
console.log("页面被隐藏:onPageHide");
}
// 页面即将销毁
aboutToDisappear() {
console.log("页面即将销毁:aboutToDisappear");
}
}
运行结果:
- 打开页面:
aboutToAppear→build()→onPageShow - 跳转到新页面:
onPageHide - 返回到该页面:
onPageShow - 退出页面:
onPageHide→aboutToDisappear
常见使用场景:
- 在
aboutToAppear()中请求网络数据 - 在
onPageShow()中开始播放视频 - 在
onPageHide()中暂停视频播放 - 在
aboutToDisappear()中取消网络请求
三、路由导航基础
鸿蒙应用中,页面之间的跳转是通过router模块实现的。路由就像是应用内部的导航系统,帮你在不同页面之间切换。
3.1 配置路由表
在进行页面跳转之前,你需要先在main_pages.json文件中配置路由表。
打开entry/src/main/resources/base/profile/main_pages.json:
json
{
"src": [
"pages/Index",
"pages/Login",
"pages/Home"
]
}
每添加一个新页面,都要在这里注册对应的路由路径,否则无法跳转。
3.2 常用路由跳转方式
1. push跳转(最常用)
添加一个新页面到路由栈顶部,当前页面会被保留在栈中。点击返回按钮可以回到上一个页面。
typescript
import router from '@ohos.router';
// 跳转到首页
router.pushUrl({
url: 'pages/Home'
});
2. replace跳转
替换当前页面,当前页面会被销毁。点击返回按钮不会回到这个页面。
typescript
// 用首页替换当前登录页
router.replaceUrl({
url: 'pages/Home'
});
使用场景: 登录成功后跳转到首页,这时候用户不应该能返回到登录页。
3. 返回上一页
typescript
// 返回上一个页面
router.back();
4. 返回指定页面
typescript
// 返回到首页
router.back({
url: 'pages/Home'
});
四、页面间数据传递
页面跳转时,经常需要把数据从一个页面传递到另一个页面。鸿蒙提供了几种简单高效的数据传递方式。
4.1 通过路由参数传递(最常用)
这是最简单也是最常用的数据传递方式,适合传递少量数据。
发送方(登录页):
typescript
import router from '@ohos.router';
// 跳转到首页,并传递用户名
router.pushUrl({
url: 'pages/Home',
params: {
username: '张三',
userId: 123456
}
});
接收方(首页):
typescript
import router from '@ohos.router';
@Entry
@Component
struct Home {
// 接收传递过来的参数
private params: Record<string, Object> = router.getParams() as Record<string, Object>;
private username: string = this.params.username as string;
private userId: number = this.params.userId as number;
build() {
Column() {
Text(`欢迎你,${this.username}`)
.fontSize(24);
Text(`你的用户ID是:${this.userId}`)
.fontSize(18)
.margin({ top: 10 });
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center);
}
}
4.2 传递复杂对象
你也可以传递复杂的对象:
typescript
// 定义用户对象
interface User {
username: string;
age: number;
gender: string;
}
// 发送方
const user: User = {
username: '李四',
age: 25,
gender: '男'
};
router.pushUrl({
url: 'pages/Home',
params: {
user: user
}
});
// 接收方
private params: Record<string, Object> = router.getParams() as Record<string, Object>;
private user: User = this.params.user as User;
五、实战:从登录页跳转到首页并传递用户信息
现在我们把前面学的所有内容结合起来,实现一个完整的登录跳转流程:
- 用户在登录页输入用户名和密码
- 点击登录按钮,验证成功后跳转到首页
- 将用户名传递给首页,在首页显示欢迎信息
- 在各个生命周期方法中添加日志,观察调用顺序
5.1 第一步:创建首页
在pages目录下创建一个新的文件Home.ets:
typescript
import router from '@ohos.router';
import hilog from '@ohos.hilog';
const TAG: string = 'HomePage';
const DOMAIN: number = 0x0000;
@Entry
@Component
struct Home {
// 接收登录页传递过来的用户名
private params: Record<string, Object> = router.getParams() as Record<string, Object>;
private username: string = this.params?.username as string || "游客";
build() {
Column() {
Text(`欢迎回来,${this.username}!`)
.fontSize(28)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 30 });
Text("这是首页")
.fontSize(20)
.margin({ bottom: 50 });
Button("退出登录")
.width(200)
.height(50)
.backgroundColor('#ff3b30')
.onClick(() => {
// 退出登录,返回登录页
router.replaceUrl({
url: 'pages/Login'
});
});
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center);
}
aboutToAppear() {
hilog.info(DOMAIN, TAG, "首页即将显示:aboutToAppear");
}
onPageShow() {
hilog.info(DOMAIN, TAG, "首页完全显示:onPageShow");
}
onPageHide() {
hilog.info(DOMAIN, TAG, "首页被隐藏:onPageHide");
}
aboutToDisappear() {
hilog.info(DOMAIN, TAG, "首页即将销毁:aboutToDisappear");
}
}
5.2 第二步:修改登录页
修改我们上一篇文章写的登录页,添加跳转逻辑:
typescript
import router from '@ohos.router';
import hilog from '@ohos.hilog';
const TAG: string = 'LoginPage';
const DOMAIN: number = 0x0000;
@Entry
@Component
struct LoginPage {
@State username: string = "";
@State password: string = "";
@State isPasswordVisible: boolean = false;
@State isLoading: boolean = false;
build() {
Column() {
// Logo和标题部分和之前一样,这里省略...
// 用户名输入框
TextInput({ placeholder: "请输入手机号/用户名", text: this.username })
.width('85%')
.height(50)
.padding({ left: 15, right: 15 })
.backgroundColor('#f5f5f5')
.borderRadius(8)
.margin({ bottom: 15 })
.onChange((value) => {
this.username = value;
});
// 密码输入框
// 这里省略...
// 登录按钮
Button(this.isLoading ? "登录中..." : "登录")
.width('85%')
.height(50)
.backgroundColor(this.isLoginButtonEnabled() ? '#007aff' : '#cccccc')
.fontSize(18)
.borderRadius(8)
.enabled(this.isLoginButtonEnabled() && !this.isLoading)
.onClick(() => {
this.handleLogin();
});
// 底部链接
// 这里省略...
}
.width('100%')
.height('100%')
.backgroundColor('#ffffff');
}
isLoginButtonEnabled(): boolean {
return this.username.length > 0 && this.password.length > 0;
}
handleLogin() {
// 简单的输入验证
if (this.username.length < 3) {
console.log("用户名长度不能少于3位");
return;
}
if (this.password.length < 6) {
console.log("密码长度不能少于6位");
return;
}
// 模拟登录请求
this.isLoading = true;
setTimeout(() => {
this.isLoading = false;
hilog.info(DOMAIN, TAG, `登录成功!用户名:${this.username}`);
// 登录成功,跳转到首页,并传递用户名
router.replaceUrl({
url: 'pages/Home',
params: {
username: this.username
}
});
}, 2000);
}
aboutToAppear() {
hilog.info(DOMAIN, TAG, "登录页即将显示:aboutToAppear");
}
onPageShow() {
hilog.info(DOMAIN, TAG, "登录页完全显示:onPageShow");
}
onPageHide() {
hilog.info(DOMAIN, TAG, "登录页被隐藏:onPageHide");
}
aboutToDisappear() {
hilog.info(DOMAIN, TAG, "登录页即将销毁:aboutToDisappear");
}
}
5.3 第三步:配置路由表
打开main_pages.json,确保首页已经注册:
json
{
"src": [
"pages/Login",
"pages/Home"
]
}
5.4 运行效果
- 应用启动后显示登录页
- 输入用户名和密码,点击登录
- 登录成功后跳转到首页,显示欢迎信息
- 点击"退出登录"按钮,返回到登录页
你可以在DevEco Studio的日志窗口中,看到各个生命周期方法的调用顺序,这样就能更直观地理解页面的生命周期了。
总结
今天我们学习了鸿蒙应用的生命周期和页面跳转,这是开发任何鸿蒙应用都必须掌握的基础知识。
核心要点总结:
- 应用生命周期有四个阶段:Create、Foreground、Background、Destroy
- 页面生命周期有四个核心回调:aboutToAppear、onPageShow、onPageHide、aboutToDisappear
- 使用router模块进行页面跳转,常用的有pushUrl和replaceUrl两种方式
- 通过路由参数可以在页面之间传递数据,支持基本类型和复杂对象
- 一定要在合适的生命周期方法中做合适的事情,避免出现内存泄漏和状态错误
福利时间!
我已经为大家准备了路由导航完整示例代码,包含了所有常用的跳转方式、数据传递方法,还有生命周期的详细演示。下载后直接导入DevEco Studio就能运行。
获取方式:
关注我的账号,私信回复"路由导航",即可免费获取完整源码!
下一篇文章,我会带大家深入学习鸿蒙的状态管理,教你如何在多个组件和多个页面之间共享数据。如果这篇文章对你有帮助,别忘了点赞、收藏、转发给你的朋友!有任何问题,欢迎在评论区留言。