【鸿蒙实战开发】HarmonyOS应用内的生命周期流转

80 篇文章 0 订阅
80 篇文章 0 订阅

两种生命周期原理与介绍

  1. UIAbility组件生命周期。

UIAbility组件是一种包含UI的应用组件,主要用于和用户交互。UIAbility组件是系统调度的基本单元,为应用提供绘制界面的窗口。一个应用可以包含一个或多个UIAbility组件。例如在支付应用中,可以将入口功能和收付款功能分别配置为独立的UIAbility。

更多内容可查看:​​Stage模型应用组件​​和​​UIAbility组件​​。

当用户打开,切换和返回到对应应用时,应用中的UIAbility实例会在其生命周期的不同状态之间转换。UIAbility类提供了一系列回调,通过这些回调可以知道当前UIAbility实例的某个状态发生改变,会经过UIAbility实例的创建和销毁,或者UIAbility实例发生了前后台的状态切换。UIAbility的生命周期包括Create,Foreground,Background,Destroy四个状态。
image.png

UIAbility实例创建完成之后,在进入Foreground之前,系统会创建一个WindowStage。WindowStage创建完成后会进入onWindowStageCreate()回调,可以在该回调中设置UI加载,设置WindowStage的事件订阅。

image.png

1. 页面/组件生命周期
Navigation生命周期

image.png

针对一次操作同步销毁和创建同步创建的场景(如replace),遵循以下规则:

− 涉及到页面的生命周期顺序aboutToAppear(外层自定义组件) -> onWillAppear(进场Destination页面) -> onWillHide(退出Destination页面) -> onAppear(进场页面) -> onWillShow(进场页面) -> onHide(退出页面) -> onWillDisAppear(退场页面) -> onShow(进场页面) -> onDisAppear(退场页面) -> aboutToDisAppear(退场页面)。

− 针对willShow和willHide生命周期有2种情形不会触发:前后台切换,router+Navigation混合使用,使用router跳转导致Navigation中的页面隐藏或者显示时不会触发willShow/willHide的流程。

− Dialog场景触发规则遵循show相关的生命周期(onWillShow,onShow)均从栈底到栈顶依次触发,hide相关生命周期(onWillHide,onHide)均从栈顶到栈底依次触发。

− 一次性清理多个页面,触发多个页面销毁(clear),对应的触发流程为栈顶页面最后销毁,堆栈中的其他页面从栈顶到栈底依次触发onHide -> onWillDisAppear -> onDisAppear。

− clear1,2,3页面,组件生命周期执行顺序, 当前页面是3(1). 销毁除当前页面的其他页面:从栈顶向栈底依次触发onHide -> onWillDisAppear -> onDisAppear(2). 销毁当前页面:onHide -> onWillDisAppear -> onDisAppear。

router

自定义组件的生命周期回调函数用于通知用户该自定义组件的生命周期,这些回调函数是私有的,在运行时由开发框架在特定的时间进行调用,不能从应用程序中手动调用这些回调函数。

image.png

可参考:​​生命周期定义​​。

实际场景中生命周期的应用

场景一:启动框架的手动配置时机选择(性能优化)
场景描述以及生命周期钩子选择

场景:启动框架预加载SDK手动配置时选择。

生命周期:UIAbility生命周期的 onCreate() 回调。

方案说明

在UIAbility的onCreate生命周期回调中进行SDK或者任务初始化。

image.png

代码实现
export default class EntryAbility extends UIAbility { 
    Logger.info('Ability onCreate') 
    // 缓存应用状态: context 
    AppStorage.setOrCreate('context', this.context) 
    let startParams = ['StartupTask_005'] 
    try { 
      startupManager.run(startParams).then(() => { 
        Logger.info(`StartupTest startupManager run then, startParams = ${JSON.stringify(startParams)}`) 
      }).catch((error: BusinessError) => { 
        Logger.error(`StartupTest promise catch error, error = ${JSON.stringify(error)}; StartupTest promise catch error, startParams = ${JSON.stringify(startParams)}`) 
      }) 
    } catch (error) { 
      Logger.error(`Startup catch error , err = ${JSON.stringify(error)}`) 
    } 
  //... 
}
场景二:应用状态初始化(定义全局变量等)
场景描述以及生命周期钩子选择

场景:

  1. 将应用状态 EntryAbility中的context和windowStage存储在AppStorage中,以便于其它业务模块使用。

  2. 注册全局字体。

  3. 初始化启动页,欢迎页,广告页。

生命周期:

  1. UIAbility生命周期的 onCreate()回调,

  2. UIAbility生命周期的 onWindowStageCreate()回调。

在onCreate设置 context上下文。在onWindowStageCreate回调中初始化页面,将windowStage储存到AppStorage,windowStage.loadContent加载页面。

核心代码
// 设置全局变量/注册自定义字体  
onWindowStageCreate(windowStage: window.WindowStage): void { 
  Logger.info('Ability onWindowStageCreate') 
  // 缓存应用状态: windowStage 
  AppStorage.setOrCreate('windowStage', windowStage) 
  // 获取应用权限 
  reqPermissionsFromUser(permissions, this.context) 
  // 启动页,广告页,欢迎页加载 
  windowStage.loadContent('pages/Welcome/Welcome', (err) => { 
    if (err.code) { 
      Logger.error(`Failed to load the content, err = ${JSON.stringify(err)}`) 
      return 
    } 
    // 注册全局字体 
    FontRegister.registerCustomFont() 
    Logger.info('Succeeded in loading the content') 
  }) 
}
// 其他模块使用 
import { common } from '@kit.AbilityKit'; 
import { window } from '@kit.ArkUI'; 

@Entry 
@Component 
struct Index { 
  @State message: string = 'Hello World'; 
  context: common.UIAbilityContext | null = AppStorage.get('context') || null 
  @StorageLink('windowStage') windowStage: window.WindowStage | null = AppStorage.get('windowStage') || null 
  // ... 
}
场景三:页面初始化
场景描述以及生命周期钩子选择

场景:

  1. Ajax数据请求。

  2. 权限获取以及地图定位功能。

  3. 定时器的开启与关闭。

生命周期:

  1. 页面生命周期的aboutToAppear(),aboutToDisappear()回调。

  2. 页面生命周期的onPageShow(),onPageHide()回调。

方案说明
  1. 在aboutToAppear生命周期回调 加载应用数据和授权。

  2. 在aboutToDisappear生命周期回调中关闭定时器。

代码实现

主页面关键代码:

import { common } from '@kit.AbilityKit'; 
import Logger from '../Utils/Logger' 
import { window } from '@kit.ArkUI'; 
import { BusinessError } from '@kit.BasicServicesKit'; 
import { getProjectList } from '../api/index' 

@Entry 
@Component 
struct Index { 
  @State message: string = 'Hello World'; 
  context: common.UIAbilityContext | null = AppStorage.get('context') || null 
  @StorageLink('windowStage') windowStage: window.WindowStage | null = AppStorage.get('windowStage') || null 
  subWindowClass: window.Window | null = null; 
  @State loading: boolean = false 
  @State list: string[] = [] 
  private appCtx: common.Context | undefined 
  private msgText: string = '我是消息' 
  private msgId: number = 0 

  aboutToAppear(): void { 
    // 获取appContext 信息 
    this.getAppCtx() 
    // 获取应用数据 
    this.initList() 
  } 

  getAppCtx() { 
    try { 
      this.appCtx = this.context?.getApplicationContext() 
      Logger.info(`applicationContext : ${JSON.stringify(this.appCtx)}`) 
    } catch (error) { 
      Logger.error(`getApplicationContext failed, error.code: ${error.code}, error.message: ${error.message}`) 
    } 
    Logger.info(`windowStage : ${JSON.stringify(this.windowStage)}`) 
  } 

  onPageShow(): void { 
    this.initList() 
  } 

  /* 获取业务数据 */ 
  async initList() { 
    this.loading = true 
    const res = await getProjectList() 
    this.loading = false 
    if (res.code === 200 && res.data) { 
      this.list = res.data 
    } 
  } 

  //... 
}

子窗口页面关键代码:

import Util from '../Utils/Util' 
import Logger from '../Utils/Logger' 
import { MapComponent, mapCommon, map } from '@kit.MapKit' 
import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit' 
import geoLocationManager from '@ohos.geoLocationManager' 
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl' 

@Entry 
@Component 
struct WindowPage { 
  @State message: string = '子窗口'; 
  @State currentTime: string = Util.getCurrentTime() 
  timer: number | null = null 
  /* 地图相关 */ 
  TAG = "HuaweiMapDemo" 
  mapOption?: mapCommon.MapOptions 
  callback?: AsyncCallback<map.MapComponentController> 
  mapController?: map.MapComponentController 
  // 纬度 
  @State lat: Number = -1 
  //经度 
  @State lng: Number = -1 

  aboutToAppear(): void { 
    // 应用授权 
    this.requestLocationPermissions() 
    // 初始化地图 
    this.initMapOption() 
  } 

  onPageShow(): void { 
    Logger.info(`onPageShow`) 
    this.timer = setInterval(() => { 
      this.currentTime = Util.getCurrentTime() 
      Logger.info('当前时间: ', `${this.currentTime}`) 
    }, 1000) 
    this.getLocation() 
    Logger.info(`开启定时器`, '') 
  } 

  onPageHide(): void { 
    Logger.info(`onPageHide`) 
  } 

  aboutToDisappear(): void { 
    Logger.info(`aboutToDisappear`) 
    this.timer && clearInterval(this.timer) 
    Logger.info(`页面销毁-关闭定时器: ${this.timer}`) 
  } 

  initMapOption() { 
    // 地图初始化参数,设置地图中心点坐标及层级 
    this.mapOption = { 
      position: { 
        target: { 
          latitude: 39.9, 
          longitude: 116.4 
        }, 
        zoom: 10 
      } 
    } 

    // 地图初始化的回调 
    this.callback = async (err, mapController) => { 
      if (!err) { 
        // 获取地图的控制器类,用来操作地图 
        this.mapController = mapController 
        this.mapController.on("mapLoad", () => { 
          console.info(this.TAG, `on-mapLoad`); 
        }) 

        // 执行自定义的方法 
        this.customizedMethod() 
      } 
    } 
  } 

  /* 获取当前经纬度 */ 
  getLocation() { 
    Logger.info('获取定位权限') 
    let requestInfo: geoLocationManager.CurrentLocationRequest = { 
      priority: 0x203, 
      scenario: geoLocationManager.LocationRequestScenario.DAILY_LIFE_SERVICE, 
      maxAccuracy: 1000, 
      timeoutMs: 5000 
    } 
    if (geoLocationManager.isLocationEnabled()) { 
      Logger.info('A:定位已使能') 
    } else { 
      Logger.info('A:定位未使能') 
    } 
    try { 
      geoLocationManager.getCurrentLocation(requestInfo, (err, location) => { 
        if (err) { 
          Logger.error(`定位失败,失败原因为:${err.message}`) 
          return 
        } 
        console.info('位置获取成功') 

        this.lat = location.latitude 
        this.lng = location.longitude 
        console.info('this.lat = ' + this.lat) 
        console.info('this.lng = ' + this.lng) 
      }) 
    } catch (err) { 
      Logger.error(`报错原因为: ${err}`) 
    } 
  } 

  private requestLocationPermissions() { 
    const permissions: Array<Permissions> = ["ohos.permission.APPROXIMATELY_LOCATION", "ohos.permission.LOCATION"] 
    let atManager = abilityAccessCtrl.createAtManager() 
    // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗 
    atManager.requestPermissionsFromUser(getContext(this), permissions).then((data) => { 
      let grantStatus: Array<number> = data.authResults 
      let length: number = grantStatus.length 
      for (let i = 0; i < length; i++) { 
        if (grantStatus[i] === 0) { 
          // 用户授权,可以继续访问目标操作 
          return 
        } else { 
          // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限 
          return; 
        } 
      } 
    }).catch((err: BusinessError) => { 
      Logger.error(`requestPermissionsFromUser failed, code is ${err.code}, message is ${err.message}`) 
    }) 
  } 

  //... 
}
场景四:状态监听,消息发布订阅

场景:某些场景下需要使用消息的发布订阅模式去实现业务功能,发布消息,订阅消息,改变页面。

生命周期:

  1. 页面生命周期的aboutToAppear(),aboutToDisappear()回调。

  2. 页面生命周期的 onPageShow(),onPageHide()回调。

当页面或者组件需要使用消息机制处理业务逻辑时,消息的发布订阅时机选择。aboutToAppear生命周期回调中订阅消息,aboutToDisappear生命周期回调中取消订阅。

代码实现

主页面关键代码:点击按钮发布消息:

import { common } from '@kit.AbilityKit'; 
import { router, window } from '@kit.ArkUI'; 
import { BusinessError } from '@kit.BasicServicesKit'; 
import { getProjectList } from '../api/Index'; 
import { emitter } from '@kit.BasicServicesKit'; 
import { MsgComp } from '../pages/components/CustomComp/CustomComp'; 
import Logger from '../Utils/Logger'; 

@Entry 
@Component 
struct Index { 
  @State message: string = 'Hello World'; 
  context: common.UIAbilityContext | null = AppStorage.get('context') || null; 
  @StorageLink('windowStage') windowStage: window.WindowStage | null = AppStorage.get('windowStage') || null; 
  subWindowClass: window.Window | null = null; 
  @State loading: boolean = false; 
  @State list: string[] = []; 
  @State showComp: boolean = false; 
  @State msgTimerId: number | undefined = undefined; 
  private appCtx: common.Context | undefined; 
  private msgText: string = '我是消息'; 
  private msgId: number = 0; 

  changeCustomComp() { 
    this.showComp = !this.showComp 
    if (!this.showComp) { 
      this.closeTimer() 
    } 
  } 

  changeMsg() { 
    if (!this.msgTimerId) { 
      this.startMsg() 
    } else { 
      this.closeTimer() 
    } 
  } 

  startMsg() { 
    this.msgTimerId = setInterval(() => { 
      this.msgId++ 
      const eventData: emitter.EventData = { 
        data: { 
          "content": this.msgText + this.msgId, 
        } 
      } 
      Logger.info('发送消息:', JSON.stringify(eventData)) 
      emitter.emit('emitterMsg', eventData) 
    }, 1000) 
  } 

  closeTimer() { 
    this.msgTimerId && clearInterval(this.msgTimerId) 
    this.msgTimerId = undefined 
    this.msgId = 0 
  } 

  //... 
}

子组件核心代码:订阅消息,取消订阅:

import { emitter } from '@kit.BasicServicesKit'; 
import Logger from '../../../Utils/Logger'; 
import type { EmitterEventData } from '../../../types/common.d'; 

@Component 
export struct MsgComp { 
  @State msg: string | undefined = '--' 

  aboutToAppear(): void { 
    // 订阅消息 
    emitter.on('emitterMsg', (e: emitter.EventData) => { 
      Logger.info(`收到消息:${JSON.stringify(e)}`) 
      const data: EmitterEventData | undefined = e.data 
      if (data) { 
        this.msg = data.content 
      } 
    }) 
  } 

  aboutToDisappear(): void { 
    // 取消订阅 
    emitter.off('emitterMsg') 
    Logger.info('取消订阅') 
  } 

  build() { 
    Column() { 
      Row() { 
        Text('我是自定义组件') 
      }.width('100%').height('50%') 

      Row() { 
        Text(`这是我订阅的消息: ${this.msg}`).margin({ 
          top: 10 
        }) 
      }.width('100%').height('50%') 
    } 
    .width('100%') 
    .height(100) 
    .border({ 
      width: 1, 
    }) 
  } 
}
场景五:NavDestination生命周期时序

针对 NavDestination 的使用以及生命周期回调,主要研究push,pop,replace,clear四种API与Navigation生命周期的关系。

Navigation的push场景
  1. 触发API与调用时机

NavPathStack.pushPath()

  1. 效果展示与执行结果:

image.png

image.png

Navigation的pop场景
  1. 触发API与调用时机

NavPathStack.pop()

  1. 效果展示与执行结果:

image.png

image.png

Navigation的replace场景

触发API与调用时机

NavPathStack.replacePath()

调用方式:pageOne使用replacePath跳转到pageTwo。

页面1与页面2的生命周期执行顺序:

image.png

本场景示例代码:

// 该示例演示NavDestination的生命周期时序。 

// 该示例演示NavDestination的生命周期时序。 
import { router } from '@kit.ArkUI' 
import Logger from '../../Utils/Logger' 

@Builder 
export function pagesMap(name: string, param: Object) { 
  if (name === 'page1') { 
    Page1() 
  } else if (name === 'page2') { 
    Page2() 
  } else if (name === 'page3') { 
    Page3() 
  } 
} 

@Component 
struct Page1 { 
  @State eventStr: string = '' 
  private stack: NavPathStack | null = null 
  build() { 
    NavDestination() { 
      Column() { 
        Text('event: ' + this.eventStr) 
        Button('pushPath', { stateEffect: true, type: ButtonType.Capsule }) 
          .width('80%') 
          .height(40) 
          .margin(20) 
          .onClick(() => { 
            if (this.stack) { 
              this.stack.pushPath({ name: 'page2' }) 
            } 
          }) 
        Button('pop', { stateEffect: true, type: ButtonType.Capsule }) 
          .width('80%') 
          .height(40) 
          .margin(20) 
          .onClick(() => { 
            this.stack?.pop() 
          }) 

        Button('replace', { stateEffect: true, type: ButtonType.Capsule }) 
          .width('80%') 
          .height(40) 
          .margin(20) 
          .onClick(() => { 
            this.stack?.replacePath({ name: 'page2' }) 
          }) 

        Button('clear', { stateEffect: true, type: ButtonType.Capsule }) 
          .width('80%') 
          .height(40) 
          .margin(20) 
          .onClick(() => { 
            this.stack?.clear() 
          }) 
      } 
      .width('100%') 
      .height('100%') 
    } 
    .title('page1') 
    .onAppear(() => { 
      this.eventStr += '<onAppear>' 
      Logger.info('NavDestination-life-page1: onAppear') 
    }) 
    .onDisAppear(() => { 
      this.eventStr += '<onDisAppear>' 
      Logger.info('NavDestination-life-page1: onDisAppear') 
    }) 
    .onShown(() => { 
      this.eventStr += '<onShown>' 
      Logger.info('NavDestination-life-page1: onShown') 
      if (this.stack) { 
        Logger.info(`页面栈长度: ${this.stack.size().toString()}`) 
      } 
    }) 
    .onHidden(() => { 
      this.eventStr += '<onHidden>' 
      Logger.info('NavDestination-life-page1: onHidden') 
    }) 
    // onReady会在onAppear之前调用 
    .onReady((ctx: NavDestinationContext) => { 
      try { 
        this.eventStr += '<onReady>' 
        this.stack = ctx.pathStack 
        Logger.info('NavDestination-life-page1: onReady') 
      } catch (e) { 
        Logger.info(`testTag onReady catch exception: ${JSON.stringify(e)}`) 
      } 
    }) 
  } 
} 

@Component 
struct Page2 { 
  @State eventStr: string = '' 
  private stack: NavPathStack | null = null 
  build() { 
    NavDestination() { 
      Column() { 
        Text('event: ' + this.eventStr) 
        Button('pushPath', { stateEffect: true, type: ButtonType.Capsule }) 
          .width('80%') 
          .height(40) 
          .margin(20) 
          .onClick(() => { 
            if (this.stack) { 
              this.stack.pushPath({ name: 'page3' }) 
            } 
          }) 
      } 
      .width('100%') 
      .height('100%') 
    } 
    .title('page2') 
    .onAppear(() => { 
      this.eventStr += '<onAppear>' 
      Logger.info('NavDestination-life-page2: onAppear') 
    }) 
    .onDisAppear(() => { 
      this.eventStr += '<onDisAppear>' 
      Logger.info('NavDestination-life-page2: onDisAppear') 
    }) 
    .onShown(() => { 
      this.eventStr += '<onShown>' 
      Logger.info('NavDestination-life-page2: onShown') 
      if (this.stack) { 
        Logger.info(`页面栈长度: ${this.stack.size().toString()}`) 
      } 
    }) 
    .onHidden(() => { 
      this.eventStr += '<onHidden>' 
      Logger.info('NavDestination-life-page2: onHidden') 
    }) 
    // onReady会在onAppear之前调用 
    .onReady((ctx: NavDestinationContext) => { 
      try { 
        this.eventStr += '<onReady>' 
        this.stack = ctx.pathStack 
        Logger.info('NavDestination-life-page2: onReady') 
      } catch (e) { 
        Logger.info(`testTag onReady catch exception: ${JSON.stringify(e)}`) 
      } 
    }) 
  } 
} 

@Component 
struct Page3 { 
  @State eventStr: string = '' 
  private stack: NavPathStack | null = null 
  build() { 
    NavDestination() { 
      Column() { 
        Text('event: ' + this.eventStr) 
        Button('replacePath', { stateEffect: true, type: ButtonType.Capsule }) 
          .width('80%') 
          .height(40) 
          .margin(20) 
          .onClick(() => { 
            if (this.stack) { 
              this.stack.replacePath({ name: 'page2' }) 
            } 
          }) 

        Button('pushPath', { stateEffect: true, type: ButtonType.Capsule }) 
          .width('80%') 
          .height(40) 
          .margin(20) 
          .onClick(() => { 
            if (this.stack) { 
              this.stack.replacePath({ name: 'page1' }) 
            } 
          }) 

        Button('to Index', { stateEffect: true, type: ButtonType.Capsule }) 
          .width('80%') 
          .height(40) 
          .margin(20) 
          .onClick(() => { 
            router.pushUrl({ 
              url: 'pages/NavPage/NavPage' 
            }) 
          }) 
        Button('clear', { stateEffect: true, type: ButtonType.Capsule }) 
          .width('80%') 
          .height(40) 
          .margin(20) 
          .onClick(() => { 
            if (this.stack) { 
              console.log('点击clear') 
              this.stack.clear() 
            } 
          }) 
      } 
      .width('100%') 
      .height('100%') 
    } 
    .title('page3') 
    .onAppear(() => { 
      this.eventStr += '<onAppear>' 
      console.log(`NavDestination-life-page3: onAppear`) 
    }) 
    .onDisAppear(() => { 
      this.eventStr += '<onDisAppear>' 
      console.log(`NavDestination-life-page3: onDisAppear`) 
    }) 
    .onShown(() => { 
      this.eventStr += '<onShown>' 
      console.log(`NavDestination-life-page3: onShown`) 
      if (this.stack) { 
        console.log(`页面栈长度: ${this.stack.size().toString()}`) 
      } 

    }) 
    .onHidden(() => { 
      this.eventStr += '<onHidden>' 
      console.log(`NavDestination-life-page3: onHidden`) 
    }) 
    // onReady会在onAppear之前调用 
    .onReady((ctx: NavDestinationContext) => { 
      try { 
        this.eventStr += '<onReady>' 
        this.stack = ctx.pathStack 
        console.log(`NavDestination-life-page3: onReady`) 

      } catch (e) { 
        console.log(`testTag onReady catch exception: ${JSON.stringify(e)}`) 
      } 
    }) 
  } 
} 

@Entry 
@Component 
struct NavPage { 
  private stack: NavPathStack = new NavPathStack() 

  build() { 
    Navigation(this.stack) { 
      Column() { 
        Button('pushPath', { stateEffect: true, type: ButtonType.Capsule }) 
          .width('80%') 
          .height(40) 
          .margin(20) 
          .onClick(() => { 
            this.stack.pushPath({ name: 'page1' }) 
          }) 

        Button('clear', { stateEffect: true, type: ButtonType.Capsule }) 
          .width('80%') 
          .height(40) 
          .margin(20) 
          .onClick(() => { 
            this.stack?.clear() 
          }) 
      } 
      .width('100%') 
      .height('100%') 
    } 
    .width('100%') 
    .height('100%') 
    .title('Navigation') 
    .navDestination(pagesMap) 
  } 
}

写在最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)文档用来跟着学习是非常有必要的。

这份鸿蒙(HarmonyOS NEXT)文档包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习文档能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习文档

鸿蒙(HarmonyOS NEXT)5.0最新学习路线

在这里插入图片描述

有了路线图,怎么能没有学习文档呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习文档

《鸿蒙 (OpenHarmony)开发入门教学视频》

在这里插入图片描述

《鸿蒙生态应用开发V3.0白皮书》

在这里插入图片描述

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

在这里插入图片描述

《鸿蒙开发基础》

●ArkTS语言
●安装DevEco Studio
●运用你的第一个ArkTS应用
●ArkUI声明式UI开发
.……
在这里插入图片描述

《鸿蒙开发进阶》

●Stage模型入门
●网络管理
●数据管理
●电话服务
●分布式应用开发
●通知与窗口管理
●多媒体技术
●安全技能
●任务管理
●WebGL
●国际化开发
●应用测试
●DFX面向未来设计
●鸿蒙系统移植和裁剪定制
……
在这里插入图片描述

《鸿蒙进阶实战》

●ArkTS实践
●UIAbility应用
●网络案例
……
在这里插入图片描述

获取以上完整鸿蒙HarmonyOS学习文档,请点击→纯血版全套鸿蒙HarmonyOS学习文档

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值