UIAbility概念

鸿蒙应用是基于Ability组件来开发的,UIAbilityAbility类型中的一种,是带有UI类型的Ability,为应用提供window窗口绘制以及交互。

每一个UIAbility实例,都对应于一个最近任务列表中的任务。一个UIAbility可以对应于多个页面,建议将一个独立的功能模块放到一个UIAbility中。

image

Router - UIAbility内的页面跳转

我们指定一个UIAbility可以有多个Page页面。启动一个Page是通过router来完成的。

router.pushUrl

//  在单例模式下,若栈中存在改实例,则会将实例移至栈顶,栈数量是不变的,若栈中不存在改实例,改实例则会入栈顶,栈数量+1
//  在标准模式(多实例)下,无论栈中是否存在实例,都会将新页面实例加入栈顶,栈数量+1
router.pushUrl({ url: RouteConstants.RANK_PAGE_URL,
params: { src: "main page push 传来的数据" } },
router.RouterMode.Single
)
  • url:页面路径
  • params:跳转携带的参数
  • mode:启动模式
    • Single:单例模式
      • 在单例模式下,若栈中存在改实例,则会将实例移至栈顶,栈数量是不变的,若栈中不存在改实例,改实例则会入栈顶,栈数量+1
    • Standard:多实例模式
      • 在标准模式(多实例)下,无论栈中是否存在实例,都会将新页面实例加入栈顶,栈数量+1

页面路径需要在resources/profile/main_pages.json文件中注册。在目标页面接收参数,可以在aboutToAppear接受参数。

  aboutToAppear() {
    // 实战中最好对参数属性判空,避免闪退
    let src = router.getParams()['src']
    LogUtils.d(src)
    LogUtils.d("stack size: "+router.getLength())
  }
  

返回上一页或返回指定页面,也是可以携带参数返回的。

 //  返回上一页
 router.back()
 // 返回指定页
 router.back({ url: RouteConstants.EXAMPLE_MAIN_PAGE_URL, params: { src: "来自上页的数据" } })

当返回有携带参数时,可以在目标组件页面的onPageShow()方法来接收,如下:

onPageShow() {
    // 页面显示时被调用
    // 初次创建页面时、从后台进入前台时
    LogUtils.d("onPageShow")
    LogUtils.d("stack size: " + router.getLength())
    // 接受上页返回携带的数据,注意需要判空,不然会闪退
    if (router.getParams() != null ) {
      let params = (router.getParams() as Record<string, string>)
      LogUtils.d("scr: " + params.src)
    
    }

}

router.replaceUrl

router.replaceUrl的参数是与router.pushUrl是一样的,区别是启动模式的表现。

// 在单例模式下,若栈中存在实例,则会将栈顶的实例移出栈,然后将目标实例移至栈顶,栈数据-1,若栈中不存在实例,则新实例入栈顶替换原来栈顶的实例,栈数量不变
// 在标准模式(多实例)下,无论栈中是否存在实例,都会将新页面实例加入栈顶并替换原栈顶实例,栈数量不变

router.replaceUrl({ url: RouteConstants.RANK_PAGE_URL, params: { src: "main page replace 传来的数据" } })

  • 单例模式下,若栈中存在实例,则会将栈顶的实例移出栈,然后将目标实例移至栈顶,栈数据-1,若栈中不存在实例,则新实例入栈顶替换原来栈顶的实例,栈数量不变。
  • 标准模式(多实例)下,无论栈中是否存在实例,都会将新页面实例加入栈顶并替换原栈顶实例,栈数量不变。

由于当前页被替换了,因此在返回时携带参数是无效的,无法接收的。

UIAbility生命周期

从桌面点击打开应用,或者返回桌面等操作,UIAbility的生命周期都会发生变化。

export default class EntryAbility extends UIAbility {
  /**
   * 1、UIAbility实例创建时,系统会回调onCreate方法,UI不可见
   *  可以用于sdk的初始化,类似于Android的Application#onCreate()方法
   * @param want
   * @param launchParam
   */
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
 
  }

  /**
   * 6、在UIAbility销毁时触发。可以在onDestroy回调中进行系统资源的释放、数据的保存等操作。
   */
  onDestroy(): void {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
  }

  /**
   * 2、在创建UIAbility实例后,进入前台前,系统会创建一个WindowStage,然后回调onWindowStageCreate方法
   * 可以用于UI页面加载、设置WindowStage的事件订阅,其中入口页面就是在这里设置的,通过WindowStage#loadContent
   * 一个UIAbility只有一个WindowStage,
   * @param windowStage
   */
  onWindowStageCreate(windowStage: window.WindowStage): void {

    // 根页面组件就是在完成加载的
    windowStage.loadContent("pages/LoginPage", (err, data) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
    });
  }

  /**
   * 5、在UIAbility实例销毁之前,则会先进入onWindowStageDestroy回调,我们可以在该回调中释放UI页面资源。
   */
  onWindowStageDestroy(): void {

  }

  /**
   * 3、从后台(桌面、任务栏)切换到前台,ui可见
   * 可以向系统申请需要的资源,比如定位、播放视频
   */
  onForeground(): void {

  }

  /**
   * 4、从前台切换到后台,ui不可见
   * 可以释放一些资源,比如停止定位,暂停播放视频
   */
  onBackground(): void {

  }
}

用户使用应用的程序退出功能,会调用UIAbilityContextterminalSelf()方法,从而完成UIAbility销毁。或者用户使用最近任务列表关闭该UIAbility实例时,也会完成UIAbility的销毁。

UIAbility的启动模式及交互

UIAbility三种启动模式:

  • singleton(单实例模式):默认模式,每次调用startAbility()启动UIAbility时,如果应用进程中该类型的UIAbility实例已经存在,则复用系统中的UIAbility实例,系统中只存在唯一一个该UIAbility实例。
  • multiton(多实例模式):每次调用startAbility()方法时,都会在应用进程中创建一个该类型的UIAbility实例。
  • specified(指定实例模式):根据业务需要是否创建一个新的UIAbility实例。

启动UIAbility的基本使用:

一、在module.json5注册UIAbility组件

// 注册UIAbility
  {
    "name":"LaunchModeAbility", 
    "icon": "$media:ic_registration_success",
    "label": "$string:ability_test_name",
    "srcEntry": "./ets/ability/LaunchModeAbility.ets",
    "startWindowIcon": "$media:ic_registration_success",
    "startWindowBackground": "$color:start_window_background",
     // 启动模式
    "launchType": "singleton"
  }
  • name: 名称,尽量与类名一样
  • icon:图标,在后台任务栏的可以看到
  • label:UIAbility的名称
  • srcEntry:UIAbility的相对路径
  • launchType启动模式

二、启动UIAbility

通过UIAbilityContext来调用startAbility()方法来启动。

private context = getContext(this) as common.UIAbilityContext

...

// 启动
  let want = {
    bundleName:"com.xxxx.demo",
    abilityName:"LaunchModeAbility",
    moduleName:"entry",
    parameters: { src: "main page param " + this.counter }
  }
  this.context.startAbility(want)
  • bundleNameUIAbility所在应用的包名
  • abilityNameUIAbility名称
  • moduleName: UIAbility所在模块的名称
  • parameters:启动携带的参数,可以在UIAbilityonCreate()中接收。

Want实例不能通过new的方式来创造,因为没有默认的构造函数,只能通过字面量的方式来定义的一个实例。

三、接收启动的参数

export  default class LaunchModeAbility extends UIAbility{
   static readonly TAG:string = "LaunchModeAbility"
  onCreate(want: Want, param: AbilityConstant.LaunchParam){
    // 接收传递的参数
    let src = want.parameters.src
    LogUtils.d("LaunchModeAbility onCreate  src: "+src)
  }

  onDestroy(){
    LogUtils.d("LaunchModeAbility onDestroy")
  }

  onWindowStageCreate(windowStage: window.WindowStage) {
    LogUtils.d("onWindowStageCreate")
    // 加载根页面组件
    windowStage.loadContent(RouteConstants.TEST_PAGE_URL, (error, data) => {
      if (error.code) {
        LogUtils.e(error.message)
      }
    })
  }
  
}  

参考

  • https://developer.huawei.com/consumer/cn/training/course/slightMooc/C101667310940295021?ha_linker=eyJ0cyI6MTcwMTUyMDY3NDYzMiwiaWQiOiI4MmM3ZTI1MmFmMDJlMDZiODBmOGU1ZDM5ZTI5YmMyOCJ9