鸿蒙 HarmonyOS 生命周期详解,都在这里了

一、应用生命周期(UIAbility)

应用生命周期(UIAbility

生命周期说明

  • onCreate(want, launchParam): 当应用启动时,系统会首先调用onCreate方法。在这个阶段,开发者可以初始化应用所需的数据和资源。例如变量定义资源加载等,用于后续的UI展示。

  • onWindowStageCreate: UIAbility实例创建完成之后,在进入Foreground之前被调用。通常在这通过loadContent接口设置应用要加载的页面。

  • onNewWant: 当应用的UIAbility实例已创建,且UIAbility配置为singleton启动模式时,再次调用startAbility()方法启动该UIAbility实例时,只会进入该UIAbility的onNewWant()回调,不会进入其onCreate()onWindowStageCreate()生命周期回调。应用可以在该回调中更新要加载的资源和数据等,用于后续的UI展示。

  • onForeground: 当应用从后台切换到前台时,onForeground方法会被调用。可以在这重新申请系统需要的资源,在onBackground中释放重新申请系统需要的资源。

  • onBackground: 当应用从前台切换到后台时,onBackground方法会被触发。在这个阶段,可以释放不再需要的资源、执行一些后台任务、保存状态等。例如,地图应用在切换到后台后,可以在onBackground回调中停止定位功能,以节省系统资源。

  • onWindowStageDestroyUIAbility实例销毁之前时调用,可以在该回调中释放UI资源。

  • onDestroy: 在UIAbility实例销毁时触发(杀进程才可触发,点击返回键不会触发,也就是真正销毁才会触发)。可以在回调中进行系统资源的释放、数据的保存等操作。

官方:应用生命周期(UIAbility)

代码

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // 当应用启动时,系统会首先调用onCreate方法。在这个阶段,开发者可以初始化应用所需的数据和资源。
    // 例如变量定义资源加载等,用于后续的UI展示。
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // UIAbility实例创建完成之后,在进入Foreground之前被调用。
    // 通常在这通过loadContent接口设置应用要加载的页面。
    windowStage.loadContent('pages/Index', (err, data) => {
    });
  }

  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
    // 当应用的UIAbility实例已创建,且UIAbility配置为singleton模式时,再次调用startAbility()方法启动该UIAbility实例时
    // 可以在该回调中更新要加载的资源和数据等,用于后续的UI展示。
  }

  onForeground(): void {
    // 当应用从后台切换到前台时,onForeground方法会被调用。
    // 可以在这重新申请系统需要的资源,在onBackground中释放重新申请系统需要的资源。
  }

  onBackground(): void {
    // 当应用从前台切换到后台时,onBackground方法会被触发。
    // 在这个阶段,可以释放不再需要的资源、执行一些后台任务、保存状态等。
    // 例如,地图应用在切换到后台后,可以在onBackground回调中停止定位功能,以节省系统资源。
  }

  onWindowStageDestroy() {
    // UIAbility实例销毁之前时调用,可以在该回调中释放UI资源。
  }

  onDestroy() {
    // UIAbility实例销毁时触发(杀进程才可触发,点击返回键不会触发,也就是真正销毁才会触发)。可以在回调中进行系统资源的释放、数据的保存等操作。
  }
}

二、组件导航Navigation页面生命周期

Navigation是路由容器,他的生命周期都在NavDestination组件上。

NavDestination生命周期大致可分为三类:

  1. 自定义组件生命周期:aboutToAppearaboutToDisappear
  2. 通用组件(Navigation、NavDestination共有)生命周期:OnAppearOnDisAppear
  3. 自有生命周期:onWillAppear、onWillShow、onShown、onWillHide、onHidden、onWillDisappear
组件导航Navigation页面生命周期

官网:组件导航Navigation页面生命周期

生命周期说明

  • aboutToAppear:在创建自定义组件后,执行其build()函数之前执行(NavDestination创建之前),允许在该方法中改变状态变量,更改将在后续执行build()函数中生效。
  • onWillAppear:NavDestination创建后,挂载到组件树之前执行,在该方法中更改状态变量会在当前帧显示生效。
  • onAppear:通用生命周期事件,NavDestination组件挂载到组件树时执行。
  • onWillShow:NavDestination组件布局显示之前执行,此时页面不可见(应用切换到前台不会触发)。
  • onShown:NavDestination组件布局显示之后执行,此时页面已完成布局。
  • onWillHide:NavDestination组件触发隐藏之前执行(应用切换到后台不会触发)。
  • onHidden:NavDestination组件触发隐藏后执行(非栈顶页面push进栈、栈顶页面pop出栈、应用切换到后台都会触发)。
  • onWillDisappear:NavDestination组件即将销毁之前执行,如果有转场动画,会在动画前触发(栈顶页面pop出栈触发)。
  • onDisAppear:通用生命周期事件,NavDestination组件从组件树上卸载销毁时执行。
  • aboutToDisappear:自定义组件析构销毁之前执行,不允许在该方法中改变状态变量。

Navigation页面生命周期代码

import { NavigationLifecycleComponent } from './NavigationLifecycleComponent';

/**
 *组件导航Navigation页面生命周期
 */
@Entry
@Component
struct NavigationLifecyclePage {
  pathStack: NavPathStack = new NavPathStack()

  aboutToAppear(): void {
    console.log('Navigation--->页面创建后挂树的回调:aboutToAppear');
    this.pathStack.setInterception({
      // 页面跳转前拦截,允许操作栈,在当前跳转中生效。
      willShow: (from: NavDestinationContext | "navBar", to: NavDestinationContext | "navBar",
        operation: NavigationOperation, animated: boolean) => {
        if (typeof to === "string") {
          console.log('Navigation--->页面跳转前回调:NavPathStack::willShow 目标页面:首页');
        } else {
          let target: NavDestinationContext = to as NavDestinationContext;
          console.log('Navigation--->页面跳转前回调:NavPathStack::willShow 目标页面:' + target.pathInfo.name);
        }
      },
      // 页面跳转后回调,在该回调中操作栈在下一次跳转中刷新。
      didShow: (from: NavDestinationContext | "navBar", to: NavDestinationContext | "navBar",
        operation: NavigationOperation, isAnimated: boolean) => {
        if (typeof from === "string") {
          console.log('Navigation--->页面跳转后回调:NavPathStack::didShow 首页触发跳转');
        } else {
          let target: NavDestinationContext = from as NavDestinationContext;
          console.log('Navigation--->页面跳转后回调:NavPathStack::didShow ' + target.pathInfo.name + "触发跳转");
        }
        if (typeof to === "string") {
          // 可以在当前执行Navigation首页数据更新
          console.log('Navigation--->页面跳转后回调:NavPathStack::didShow 跳转到:首页');
        } else {
          let target: NavDestinationContext = to as NavDestinationContext;
          console.log('Navigation--->页面跳转后回调:NavPathStack::didShow 跳转到:' + target.pathInfo.name);
        }
      },
      // Navigation单双栏显示状态发生变更时触发该回调。
      modeChange: (mode: NavigationMode) => {
        console.log('Navigation--->Navigation单双栏显示状态发生变更时回调:NavPathStack::modeChange ' + mode);
      }
    })
  }

  build() {
    Navigation(this.pathStack) {
      Column() {
        Text("组件导航Navigation页面生命周期")
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 50 })
        NavigationLifecycleComponent().margin({ top: 20 })
        Button('组件导航NavDestination')
          .fontSize(20)
          .width('100%')
          .margin({ top: 20 })
          .onClick(() => {
            this.pathStack.pushPathByName("NavDestinationLifecyclePage", null)
          })
      }
      .height('100%')
      .width('100%')
    }
    .mode(NavigationMode.Stack)
    .onAppear(() => {
      console.log('Navigation--->组件挂载到组件树时回调:onAppear');
    })
    .onDisAppear(() => {
      console.log('Navigation--->组件从组件树上卸载销毁时回调:onDisAppear');
    })
  }

  // 页面显示时的回调,如:后台显示,其他页面返回
  onPageShow(): void {
    console.log('Navigation--->页面显示时的回调:onPageShow');
  }

  // 页面隐藏时的回调,如:切到后台,关闭页面
  onPageHide(): void {
    console.log('Navigation--->页面隐藏时的回调:onPageHide');
  }

  // 页面销毁前下树的回调
  aboutToDisappear(): void {
    console.log('Navigation--->页面销毁前下树的回调:aboutToDisappear');
  }
}

NavDestination页面生命周期

import { RouterLifecycleComponent } from './RouterLifecycleComponent';
import { router } from '@kit.ArkUI';

@Builder
export function NavDestinationLifecyclePageBuilder() {
  NavDestinationLifecyclePage()
}

/**
 *组件导航NavDestination页面生命周期
 */
@Entry
@Component
struct NavDestinationLifecyclePage {
  pathStack: NavPathStack = new NavPathStack()

  aboutToAppear(): void {
    console.log('Navigation--->NavDestination页面创建后挂树的回调:aboutToAppear');
  }

  build() {
    NavDestination() {
      Column() {
        Text("组件导航NavDestination页面生命周期")
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 50 })
        RouterLifecycleComponent().margin({ top: 20 })
        Button('组件导航NavDestination子页面')
          .fontSize(20)
          .width('100%')
          .margin({ top: 20 })
          .onClick(() => {
            this.pathStack.pushPathByName("NavDestinationLifecyclePage", null)
          })
      }
      .height('100%')
      .width('100%')
    }
    .title("组件导航NavDestination")
    .onWillAppear(() => {
      console.log('Navigation--->NavDestination创建后,挂载到组件树之前回调:onWillAppear');
    })
    .onReady((context: NavDestinationContext) => {
      console.log('Navigation--->NavDestination页面即将构建子组件之前回调:onReady');
      this.pathStack = context.pathStack
    })
    .onAppear(() => {
      console.log('Navigation--->NavDestination组件挂载到组件树时回调:onAppear');
    })
    .onWillShow(() => {
      console.log('Navigation--->NavDestination组件布局显示之前回调:onWillShow');
    })
    .onShown(() => {
      console.log('Navigation--->NavDestination组件布局显示之后回调:onShown');
    })
    .onWillHide(() => {
      console.log('Navigation--->NavDestination组件触发隐藏之前回调:onWillHide');
    })
    .onHidden(() => {
      console.log('Navigation--->NavDestination组件触发隐藏后回调:onHidden');
    })
    .onWillDisappear(() => {
      console.log('Navigation--->NavDestination组件即将销毁之前回调:onWillDisappear');
    })
    .onDisAppear(() => {
      console.log('Navigation--->NavDestination组件从组件树上卸载销毁时回调:onDisAppear');
    })
  }

  // 页面显示时的回调,如:后台显示,其他页面返回
  onPageShow(): void {
    console.log('Navigation--->NavDestination页面显示时的回调:onPageShow');
  }

  // 页面隐藏时的回调,如:切到后台,关闭页面
  onPageHide(): void {
    console.log('Navigation--->NavDestination页面隐藏时的回调:onPageHide');
  }

  // 页面销毁前下树的回调
  aboutToDisappear(): void {
    console.log('Navigation--->NavDestination页面销毁前下树的回调:aboutToDisappear');
  }
}

额外说明

NavDestination(子页面)返回到 Navigation(首页)页面生命周期onPageShow不会执行。
可以使用其他两种方式实现,不确定有没有更优解,提供两个思路给大家参考

  • 使用观察者模式,具体实现网上官网都有哈
  • 使用NavPathStack. setInterception监听方式,里面有两个函数willShow、didShow都能实现
pathStack: NavPathStack = new NavPathStack()

aboutToAppear(): void {
    console.log('Navigation--->页面创建后挂树的回调:aboutToAppear');
    this.pathStack.setInterception({
      // 页面跳转前拦截,允许操作栈,在当前跳转中生效。
      willShow: (from: NavDestinationContext | "navBar", to: NavDestinationContext | "navBar",
        operation: NavigationOperation, animated: boolean) => {
        if (typeof to === "string") {
          console.log('Navigation--->页面跳转前回调:NavPathStack::willShow 目标页面:首页');
        } else {
          let target: NavDestinationContext = to as NavDestinationContext;
          console.log('Navigation--->页面跳转前回调:NavPathStack::willShow 目标页面:' + target.pathInfo.name);
        }
      },
      // 页面跳转后回调,在该回调中操作栈在下一次跳转中刷新。
      didShow: (from: NavDestinationContext | "navBar", to: NavDestinationContext | "navBar",
        operation: NavigationOperation, isAnimated: boolean) => {
        if (typeof from === "string") {
          console.log('Navigation--->页面跳转后回调:NavPathStack::didShow 首页触发跳转');
        } else {
          let target: NavDestinationContext = from as NavDestinationContext;
          console.log('Navigation--->页面跳转后回调:NavPathStack::didShow ' + target.pathInfo.name + "触发跳转");
        }
        if (typeof to === "string") {
          // 可以在当前执行Navigation首页数据更新
          console.log('Navigation--->页面跳转后回调:NavPathStack::didShow 跳转到:首页');
        } else {
          let target: NavDestinationContext = to as NavDestinationContext;
          console.log('Navigation--->页面跳转后回调:NavPathStack::didShow 跳转到:' + target.pathInfo.name);
        }
      },
      // Navigation单双栏显示状态发生变更时触发该回调。
      modeChange: (mode: NavigationMode) => {
        console.log('Navigation--->Navigation单双栏显示状态发生变更时回调:NavPathStack::modeChange ' + mode);
      }
    })
  }

三、自定义组件生命周期

自定义组件和页面的关系

自定义组件5:@Component装饰的UI单元,可以组合多个系统组件实现UI的复用,可以调用组件的生命周期。
页面:即应用的UI页面。可以由一个或者多个自定义组件组成,@Entry装饰的自定义组件为页面的入口组件,即页面的根节点,一个页面有且仅能有一个@Entry。只有被@Entry装饰的组件才可以调用页面的生命周期。

自定义组件生命周期

生命周期说明

  • aboutToAppear:组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build()函数之前执行。
  • onDidBuild:组件build()函数执行完成之后回调该接口,开发者可以在这个阶段进行埋点数据上报等不影响实际UI的功能。不建议在onDidBuild函数中更改状态变量、使用animateTo等功能,这可能会导致不稳定的UI表现。
  • aboutToDisappear:aboutToDisappear函数在自定义组件析构销毁之前执行。不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改可能会导致应用程序行为不稳定。
@Component
export struct NavDestinationLifecycleComponent {
  aboutToAppear(): void {
    console.log('Navigation--->NavDestination自定义组件即将出现时回调:aboutToAppear');
  }

  build() {
    Column() {
      Text("组件导航NavDestination自定义组件生命周期")
        .fontSize(22)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.Orange)
    }
    .width('100%')
  }

  onDidBuild(): void {
    console.log('Navigation--->NavDestination自定义组件build()函数执行完成之后回调:onDidBuild');
  }

  aboutToDisappear(): void {
    console.log('Navigation--->NavDestination自定义组件析构销毁之前执行:aboutToDisappear');
  }
}

官网:页面和自定义组件生命周期

四、页面路由Router生命周期

Router页面生命周期为@Entry页面中的通用方法,主要有如下四个生命周期:

页面路由Router生命周期

页面

import { RouterLifecycleComponent } from './RouterLifecycleComponent';
import { router } from '@kit.ArkUI';

/**
 *页面路由Router生命周期
 */
@Entry
@Component
struct RouterLifecyclePage {
  aboutToAppear(): void {
    console.log('Router--->页面创建后挂树的回调:aboutToAppear');
  }

  build() {
    Column() {
      Text("页面路由Router生命周期")
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 50 })
      RouterLifecycleComponent().margin({ top: 20 })
      Button('页面路由Router子页面')
        .fontSize(20)
        .width('100%')
        .margin({ top: 20 })
        .onClick(() => {
          router.pushUrl({ url: "pages/demo/RouterLifecyclePage" })
        })
    }
    .height('100%')
    .width('100%')
  }

  // 页面显示时的回调,如:后台显示,其他页面返回
  onPageShow(): void {
    console.log('Router--->页面显示时的回调:onPageShow');
  }

  // 页面隐藏时的回调,如:切到后台,关闭页面
  onPageHide(): void {
    console.log('Router--->页面隐藏时的回调:onPageHide');
  }

  // 页面销毁前下树的回调
  aboutToDisappear(): void {
    console.log('Router--->页面销毁前下树的回调:aboutToDisappear');
  }
}

自定义组件

@Component
export struct RouterLifecycleComponent {
  aboutToAppear(): void {
    console.log('Router--->自定义组件即将出现时回调:aboutToAppear');
  }

  build() {
    Column() {
      Text("页面路由Router自定义组件生命周期")
        .fontSize(22)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.Orange)
    }
    .width('100%')
  }

  onDidBuild(): void {
    console.log('Router--->自定义组件build()函数执行完成之后回调:onDidBuild');
  }

  aboutToDisappear(): void {
    console.log('Router--->自定义组件析构销毁之前执行:aboutToDisappear');
  }
}

五、推荐使用组件导航Navigation原因

组件导航(Navigation)和页面路由(@ohos.router)均支持应用内的页面跳转,但组件导航支持在组件内部进行跳转,使用更灵活。组件导航具备更强的一次开发多端部署能力,可以进行更加灵活的页面栈操作,同时支持更丰富的动效和生命周期。因此,推荐使用组件导航(Navigation)来实现页面跳转以及组件内的跳转,以获得更佳的使用体验。

具体可以查看官网说明

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容