HarmonyOS

ArkTS的基本组成
装饰器:@Component表示自定义组件,@Entry表示该自定义组件为入口组件
UI描述:以声明式的方式来描述UI的结构,例如build()方法中的代码块
自定义组件:可复用的UI单元,可组合其他组件,被@Component装饰
系统组件:ArkUI框架中默认内置的基础和容器组件,可直接被开发者调用,比如示例中的Column、Text、Divider、Button。
属性方法:组件可以通过链式调用配置多项属性,如fontSize()、width()、height()、backgroundColor()等。
事件方法:组件可以通过链式调用设置多个事件的响应逻辑,如跟随在Button后面的onClick()
在这里插入图片描述
自定义组件的基本结构
struct:自定义组件基于struct实现,struct + 自定义组件名 + {…}的组合构成自定义组件,不能有继承关系。对于struct的实例化,可以省略new
@Component:@Component装饰器仅能装饰struct关键字声明的数据结构。struct被@Component装饰后具备组件化的能力,需要实现build方法描述UI,一个struct只能被一个@Component装饰
build()函数:build()函数用于定义自定义组件的声明式UI描述,自定义组件必须定义build()函数
@Entry:@Entry装饰的自定义组件将作为UI页面的入口。在单个UI页面中,最多可以使用@Entry装饰一个自定义组件

build()函数
所有声明在build()函数的语言,我们统称为UI描述,UI描述需要遵循以下规则:
(1)@Entry装饰的自定义组件,其build()函数下的根节点唯一且必要,且必须为容器组件,其中ForEach禁止作为根节点。
@Component装饰的自定义组件,其build()函数下的根节点唯一且必要,可以为非容器组件,其中ForEach禁止作为根节点。
(2)不允许声明本地变量
(3)不允许在UI描述里直接使用console.info,但允许在方法或者函数里使用
(4)不允许创建本地的作用域
(5)不允许调用没有用@Builder装饰的方法,允许系统组件的参数是TS方法的返回值
(6)不允许switch语法,如果需要使用条件判断,请使用if
(7)不允许使用表达式

@Entry
@Component
struct MyComponent {
  build() {
    // 根节点唯一且必要,必须为容器组件
    Row() {
      ChildComponent() 
    }
  }
}

@Component
struct ChildComponent {
  build() {
    // 根节点唯一且必要,可为非容器组件
    Image('test.jpg')
  }
}
不允许声明本地变量,反例如下。
build() {
  // 反例:不允许声明本地变量
  let a: number = 1;
}

build() {
  // 反例:不允许console.info
  console.info('print debug log');
}

build() {
  // 反例:不允许本地作用域
  {
    ...
  }
}

@Component
struct ParentComponent {
  doSomeCalculations() {
  }

  calcTextValue(): string {
    return 'Hello World';
  }

  @Builder doSomeRender() {
    Text(`Hello World`)
  }

  build() {
    Column() {
      // 反例:不能调用没有用@Builder装饰的方法
      this.doSomeCalculations();
      // 正例:可以调用
      this.doSomeRender();
      // 正例:参数可以为调用TS方法的返回值
      Text(this.calcTextValue())
    }
  }
}

build() {
  Column() {
    // 反例:不允许使用switch语法
    switch (expression) {
      case 1:
        Text('...')
        break;
      case 2:
        Image('...')
        break;
      default:
        Text('...')
        break;
    }
  }
}

build() {
  Column() {
    // 反例:不允许使用表达式
    (this.aVar > 10) ? Text('...') : Image('...')
  }
}

自定义组件生命周期
(1)页面生命周期,即被@Entry装饰的组件生命周期,提供以下生命周期接口:
onPageShow:页面每次显示时触发一次,包括路由过程、应用进入前台等场景。
onPageHide:页面每次隐藏时触发一次,包括路由过程、应用进入后台等场景。
onBackPress:当用户点击返回按钮时触发。
(2)组件生命周期,即一般用@Component装饰的自定义组件的生命周期,提供以下生命周期接口:
aboutToAppear:组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build()函数之前执行。
aboutToDisappear:在自定义组件析构销毁之前执行。不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改可能会导致应用程序行为不稳定。
在这里插入图片描述

页面和自定义组件生命周期
Index页面包含两个自定义组件,一个是被@Entry装饰的MyComponent,也是页面的入口组件,即页面的根节点;一个是Child,是MyComponent的子组件。只有@Entry装饰的节点才可以使页面级别的生命周期方法生效,所以MyComponent中声明了当前Index页面的页面生命周期函数。MyComponent和其子组件Child也同时也声明了组件的生命周期函数。

应用冷启动的初始化流程为:MyComponent aboutToAppear --> MyComponent build --> Child aboutToAppear --> Child build --> Child build执行完毕 --> MyComponent build执行完毕 --> Index onPageShow。
点击“delete Child”,if绑定的this.showChild变成false,删除Child组件,会执行Child aboutToDisappear方法。
点击“push to next page”,调用router.pushUrl接口,跳转到另外一个页面,当前Index页面隐藏,执行页面生命周期Index onPageHide。此处调用的是router.pushUrl接口,Index页面被隐藏,并没有销毁,所以只调用onPageHide。跳转到新页面后,执行初始化新页面的生命周期的流程。
如果调用的是router.replaceUrl,则当前Index页面被销毁,执行的生命周期流程将变为:Index onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear。上文已经提到,组件的销毁是从组件树上直接摘下子树,所以先调用父组件的aboutToDisappear,再调用子组件的aboutToDisappear,然后执行初始化新页面的生命周期流程。
点击返回按钮,触发页面生命周期Index onBackPress,且触发返回一个页面后会导致当前Index页面被销毁。
最小化应用或者应用进入后台,触发Index onPageHide。当前Index页面没有被销毁,所以并不会执行组件的aboutToDisappear。应用回到前台,执行Index onPageShow。
退出应用,执行Index onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear。

自定义组件方法
(1)@Builder装饰器:自定义构建函数
(2)@Styles装饰器:定义组件重用样式
@Styles仅支持通用属性和通用事件。
@Styles方法不支持参数。
@Styles可以定义在组件内或全局,在全局定义时需在方法名前面添加function关键字,组件内定义时则不需要添加function关键字。
定义在组件内的@Styles可以通过this访问组件的常量和状态变量,并可以在@Styles里通过事件来改变状态变量的值。
(3)@Extend装饰器:定义扩展组件样式
@Extend的仅支持定义在全局,不支持在组件内部定义
@Extend的支持封装指定组件的私有属性、私有事件和自身定义的全局方法
@Extend的参数可以为状态变量,当状态变量改变时,UI可以正常的被刷新渲染

管理组件状态
@State:装饰器表示组件内状态,状态变量变化会触发UI刷新,这个变量只能在组件内部访问
@Prop:父子单向同步,这个装饰器用于声明一个属性,它允许父组件向子组件传递数据。@Prop装饰的变量必须使用其父组件提供的@State变量进行初始化,并且允许在子组件内部进行修改。但需要注意的是,子组件对@Prop变量的修改不会通知给父组件,即@Prop属于单向数据绑定
@Link:父子双向同步,这个装饰器用于建立父子组件之间的双向数据绑定。与@Prop不同,@Link装饰的变量可以和父组件的@State变量进行双向绑定。这意味着当子组件修改@Link变量时,父组件的对应状态也会自动更新,反之亦然。需要注意的是,@Link变量不能在组件内部进行初始化。
@Observed和@ObjectLink:嵌套类对象属性变化。当对象或数组内的属性发生变化时,@State、@Prop和@Link等装饰器可能无法触发组件的更新。在这种情况下,可以使用@Observed来装饰需要监控的对象组件,同时使用@ObjectLink来装饰对象内部的属性。这样,当对象属性发生变化时,组件会相应地更新。
@Provide和@Consume:与后代组件双向同步,应用于状态数据在多个层级之间传递的场景。@Provide修饰的状态变量自动对提供者组件的所有后代组件可用,后代组件通过使用@Consume装饰的变量来获得对提供的状态变量的访问。@Provide作为数据的提供方,可以更新其子孙节点的数据,并触发页面渲染。@Consume在感知到@Provide数据的更新后,会触发当前自定义组件的重新渲染。使用@Provide的好处是开发者不需要多次将变量在组件间传递
@Watch装饰器:状态变量更改通知,需要关注某个状态变量的值是否改变,可以使用@Watch为状态变量设置回调函数
$$语法:内置组件双向同步,内置组件提供TS变量的引用,使得TS变量和系统内置组件的内部状态保持同步

管理应用拥有的状态
要实现应用级的,或者多个页面的状态数据共享,就需要用到应用级别的状态管理。
(1)LocalStorage:页面级UI状态存储,通常用于UIAbility内、页面间的状态共享。
(2)AppStorage:特殊的单例LocalStorage对象,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储;
(3)PersistentStorage:持久化存储UI状态,通常和AppStorage配合使用,选择AppStorage存储的数据写入磁盘,以确保这些属性在应用程序重新启动时的值与应用程序关闭时的值相同;
(4)Environment:应用程序运行的设备的环境参数,环境参数会同步到AppStorage中,可以和AppStorage搭配使用

UIAbility组件生命周期
(1)Create(创建) :当UIAbility被创建时,系统会调用onCreate函数。在这个阶段,开发者可以进行一些初始化操作,比如设置UI界面、加载数据等。需要注意的是,在这个阶段,UIAbility还没有被展示给用户,因此不能进行与用户交互的操作。
(2)onWindowStageCreate(窗口创建) :在UIAbility创建之后,系统会调用onWindowStageCreate函数,创建与UIAbility相关联的窗口。在这个阶段,开发者可以设置窗口的属性,比如窗口的大小、位置、背景等。
(3)Foreground(前台展示) :当UIAbility被切换到前台时,系统会调用onForeground函数。在这个阶段,UIAbility的窗口会被展示出来,用户可以与之进行交互。开发者可以在这个阶段更新UI界面,响应用户的操作等。
(4)Background(后台隐藏) :当UIAbility被切换到后台时,系统会调用onBackground函数。在这个阶段,UIAbility的窗口会被隐藏,用户无法与之进行交互。开发者可以在这个阶段进行一些后台任务的处理,比如保存数据、下载文件等。
(5)onWindowStageDestroy(窗口销毁) :在UIAbility销毁之前,系统会调用onWindowStageDestroy函数,销毁与UIAbility相关联的窗口。在这个阶段,开发者可以释放与窗口相关的资源,比如内存、文件句柄等。
(6)Destroy(销毁) :最后,当UIAbility被销毁时,系统会调用onDestroy函数。在这个阶段,开发者需要释放所有与UIAbility相关的资源,比如UI界面、数据等。一旦UIAbility被销毁,就不能再被使用。

在这里插入图片描述
UIAbility的启动模式
在module.json5配置文件中的"launchType"字段配置
(1)Singleton(单实例模式):默认情况下的启动模式。每次调用startAbility()方法时,如果应用进程中该类型的UIAbility实例已经存在,则复用系统中的UIAbility实例。系统中只存在唯一一个该UIAbility实例,即在最近任务列表中只存在一个该类型的UIAbility实例。
(2)Multiton(多实例模式):每次调用startAbility()方法时,都会在应用进程中创建一个新的该类型UIAbility实例。即在最近任务列表中可以看到有多个该类型的UIAbility实例。这种情况下可以将UIAbility配置为multiton(多实例模式)。每次创建新的实例时,都会重新走一遍UIAbility的生命周期方法。
(3)Specified(指定实例模式):针对一些特殊场景使用(例如文档应用中每次新建文档希望都能新建一个文档实例,重复打开一个已保存的文档希望打开的都是同一个文档实例)。
在UIAbility实例创建之前,允许开发者为该实例创建一个唯一的字符串Key,创建的UIAbility实例绑定Key之后,后续每次调用startAbility()方法时,都会询问应用使用哪个Key对应的UIAbility实例来响应startAbility()请求。运行时由UIAbility内部业务决定是否创建多实例,如果匹配有该UIAbility实例的Key,则直接拉起与之绑定的UIAbility实例,否则创建一个新的UIAbility实例。

UIAbility组件与UI的数据同步
(1)使用EventHub进行数据通信:基于发布订阅模式来实现,事件需要先订阅后发布,订阅者收到消息后进行处理。
(2)使用globalThis进行数据同步:ArkTS引擎实例内部的一个全局对象,在ArkTS引擎实例内部都能访问。
(3)使用AppStorage/LocalStorage进行数据同步:ArkUI提供了AppStorage和LocalStorage两种应用级别的状态管理方案,可用于实现应用级别和UIAbility级别的数据同步。

页面路由
Router两种跳转模式:
(1)router.pushUrl():目标页不会替换当前页,而是压入页面栈。这样可以保留当前页的状态,并且可以通过返回键或者调用router.back()方法返回到当前页。
(2)router.replaceUrl():目标页会替换当前页,并销毁当前页。这样可以释放当前页的资源,并且无法返回到当前页。
Router两种实例模式:
(1)Standard:标准实例模式,也是默认情况下的实例模式。每次调用该方法都会新建一个目标页,并压入栈顶。
(2)Single:单实例模式。即如果目标页的url在页面栈中已经存在同url页面,则离栈顶最近的同url页面会被移动到栈顶,并重新加载;如果目标页的url在页面栈中不存在同url页面,则按照标准模式跳转。

页面返回:
(1)返回到上一个页面。
router.back();
(2)返回到指定页面。
router.back({
url: ‘pages/Home’
});
(3)返回到指定页面,并传递自定义参数信息。
router.back({
url: ‘pages/Home’,
params:{
info: ‘来自Home页’
}
});

场景一:有一个主页(Home)和一个详情页(Detail),希望从主页点击一个商品,跳转到详情页。同时,需要保留主页在页面栈中,以便返回时恢复状态。这种场景下,可以使用pushUrl()方法,并且使用Standard实例模式(或者省略)
场景二:有一个登录页(Login)和一个个人中心页(Profile),希望从登录页成功登录后,跳转到个人中心页。同时,销毁登录页,在返回时直接退出应用。这种场景下,可以使用replaceUrl()方法,并且使用Standard实例模式(或者省略)。
场景三:有一个设置页(Setting)和一个主题切换页(Theme),希望从设置页点击主题选项,跳转到主题切换页。同时,需要保证每次只有一个主题切换页存在于页面栈中,在返回时直接回到设置页。这种场景下,可以使用pushUrl()方法,并且使用Single实例模式。
场景四:有一个搜索结果列表页(SearchResult)和一个搜索结果详情页(SearchDetail),希望从搜索结果列表页点击某一项结果,跳转到搜索结果详情页。同时,如果该结果已经被查看过,则不需要再新建一个详情页,而是直接跳转到已经存在的详情页。这种场景下,可以使用replaceUrl()方法,并且使用Single实例模式。

动画
(1)显式动画(animateTo):闭包内的变化均会触发动画,包括由数据变化引起的组件的增删、组件属性的变化等,可以做较为复杂的动画。
(2)属性动画(animation):动画设置简单,属性变化时自动触发动画
(3)组件内转场动画:transition函数的入参为组件内转场的效果,可以定义平移、透明度、旋转、缩放这几种转场样式的单个或者组合的转场效果,必须和animateTo一起使用才能产生组件转场效果。
(4)页面转场动画:两个页面间发生跳转,一个页面消失,另一个页面出现,这时可以配置各自页面的页面转场参数实现自定义的页面转场效果。页面转场效果写在pageTransition函数中,通过PageTransitionEnter和PageTransitionExit指定页面进入和退出的动画效果。
(5)页面共享元素转场:在不同页面间,有使用相同的元素(例如同一幅图)的场景,共享元素转场的接口为sharedTransition
在这里插入图片描述

并发
ArkTS支持异步并发和多线程并发。
(1)Promise和async/await提供异步并发能力,适用于单次I/O任务的开发场景。
(2)TaskPool和Worker提供多线程并发能力,适用于CPU密集型任务、I/O密集型任务和同步任务等并发场景
TaskPool和Worker均支持多线程并发能力。由于TaskPool的工作线程会绑定系统的调度优先级,并且支持负载均衡(自动扩缩容),而Worker需要开发者自行创建,存在创建耗时以及不支持设置调度优先级,故在性能方面使用TaskPool会优于Worker,因此大多数场景推荐使用TaskPool。
TaskPool偏向独立任务维度,该任务在线程中执行,无需关注线程的生命周期,超长任务(大于3分钟且非长时任务)会被系统自动回收;而Worker偏向线程的维度,支持长时间占据线程执行,需要主动管理线程生命周期。
常见的一些开发场景及适用具体说明如下:
①运行时间超过3分钟(不包含Promise和async/await异步调用的耗时,例如网络下载、文件读写等I/O任务的耗时)的任务。例如后台进行1小时的预测算法训练等CPU密集型任务,需要使用Worker。
②有关联的一系列同步任务。例如在一些需要创建、使用句柄的场景中,句柄创建每次都是不同的,该句柄需永久保存,保证使用该句柄进行操作,需要使用Worker。
③需要设置优先级的任务。例如图库直方图绘制场景,后台计算的直方图数据会用于前台界面的显示,影响用户体验,需要高优先级处理,需要使用TaskPool。
④需要频繁取消的任务。例如图库大图浏览场景,为提升体验,会同时缓存当前图片左右侧各2张图片,往一侧滑动跳到下一张图片时,要取消另一侧的一个缓存任务,需要使用TaskPool。
⑤大量或者调度点较分散的任务。例如大型应用的多个模块包含多个耗时任务,不方便使用Worker去做负载管理,推荐采用TaskPool。

配置信息
app.json5主要包含以下内容:
应用的全局配置信息,包含应用的包名、开发厂商、版本号等基本信息。
特定设备类型的配置信息。
module.json5主要包含以下内容:
Module的基本配置信息,例如Module名称、类型、描述、支持的设备类型等基本信息。
应用组件信息,包含UIAbility组件和ExtensionAbility组件的描述信息。
应用运行过程中所需的权限信息。

AppScope > app.json5:应用的全局配置信息。
entry:HarmonyOS工程模块,编译构建生成一个HAP包。
src > main > ets:用于存放ArkTS源码。
src > main > ets > entryability:应用/服务的入口。
src > main > ets > pages:应用/服务包含的页面。
src > main > resources:用于存放应用/服务所用到的资源文件,如图形、多媒体、字符串、布局文件等。关于资源文件,详见资源分类与访问。
src > main > module.json5:Stage模型模块配置文件。主要包含HAP包的配置信息、应用/服务在具体设备上的配置信息以及应用/服务的全局配置信息。具体的配置文件说明,详见module.json5配置文件。
build-profile.json5:当前的模块信息、编译信息配置项,包括buildOption、targets配置等。其中targets中可配置当前运行环境,默认为HarmonyOS。
hvigorfile.ts:模块级编译构建任务脚本,开发者可以自定义相关任务和代码实现。
oh_modules:用于存放三方库依赖信息。关于原npm工程适配ohpm操作,请参考历史工程迁移。
build-profile.json5:应用级配置信息,包括签名、产品配置等。
hvigorfile.ts:应用级编译构建任务脚本。

在这里插入图片描述
优化应用的性能
(1)性能分析:首先,使用鸿蒙OS提供的性能分析工具来评估应用的性能。这些工具可以帮助你识别性能瓶颈,如CPU使用率、内存消耗、渲染速度等。
(2)代码优化:
减少不必要的计算:避免在UI线程中进行复杂的计算,这样可以防止界面卡顿。
使用异步编程:对于可能阻塞主线程的操作,如网络请求、文件读写等,使用异步编程模式。
优化数据结构和算法:选择高效的数据结构和算法,以减少内存使用和计算时间。
(3)内存管理:
避免内存泄漏:确保不再使用的资源被正确释放。
合理使用缓存:适当使用缓存可以提高性能,但要避免缓存过大导致内存不足。
优化图片资源:压缩图片大小,减少内存占用。
(4)网络优化:
减少网络请求:合并多个请求,减少网络延迟。
使用缓存策略:对于频繁请求的数据,使用缓存策略来减少网络请求。
(5)数据库优化:
合理使用索引:为数据库表添加合适的索引,提高查询效率。
避免频繁读写:批量操作可以减少数据库操作的次数。
(6)界面优化:
减少界面层级:简化界面布局,减少不必要的视图层级。
使用高效的绘图API:选择性能更好的绘图API来渲染界面。
(7)日志和监控:
添加日志记录:在关键代码路径中添加日志记录,以便追踪性能问题。
使用监控工具:使用鸿蒙OS提供的监控工具来实时监控应用的性能。

  • 29
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值