鸿蒙性能优化之布局优化

避免在生命周期函数执行耗时操作

在build函数执行之前,将先执行aboutToAppear()生命周期回调函数。若在该函数中执行耗时操作,将阻塞UI渲染,增加UI主线程负担。可以将耗时操作放到子线程或者使用不耗时的函数。例如在aboutToAppear中应该避免使用ResourceManager的getXXXSync接口入参中直接使用资源信息,推荐使用资源id作为入参,推荐用法为:resourceManager.getStringSync($r('app.string.test').id)。第一种方式获取的是拷贝对象,发生了一次深拷贝,第二种方式直接获取原对象的引用。

使用@Builder方法代替自定义组件

在ArkUI中使用自定义组件时,在build阶段将在后端FrameNode树创建一个相应的CustomNode节点,在渲染阶段时也会创建对应的RenderNode节点,如下图所示。   减少自定义组件的使用,尤其是自定义组件在循环中的使用,将成倍减少FrameNode节点树上CustomNode节点数量,有效缩短页面的加载和渲染时长。@Builder函数不会在后端FrameNode节点树上创建一个新的树节点。如果组件仅仅是用来纯展示,不需要更新,优先使用@Builder函数代替自定义组件。

按需注册组件属性

组件每个属性保存在FrameNode节点上,组件设置了大量属性且该组件被大量使用,对应用的整体性能会产生较大影响。应按需注册组件属性,避免设置冗余属性。如果必须设置很多属性,可以考虑AttributeModifier动态注册组件属性的方式。动态注册组件属性可以实现差异更新属性,当组件创建或者更新时,重新执行组件的样式属性对象的更新接口。通过key找到对应的属性修改器对象进行差异对比,若有更新变化再通知native侧进行属性更新。

scss 复制代码
// 1.自定义属性修改器,该类实现了AttributeModifier接口
class RowModifier implements AttributeModifier<RowAttribute> {
  private customImage: ResourceStr = '';
  private static instance: RowModifier;

  constructor() {}

  setCustomImage(customImage: ResourceStr) {
    this.customImage = customImage;
    return this;
  }
  // 采用单例模式,避免为每个组件都创建一个新的修改器,增加创建产生的性能开销
  public static getInstance(): RowModifier {
    if (!RowModifier.instance) {
      RowModifier.instance = new RowModifier();
    }
    return RowModifier.instance;
  }
  // 2.实现AttributeModifier接口的applyNormalAttribute方法,自定义属性设置的逻辑
  applyNormalAttribute(instance: RowAttribute) {
    if (this.customImage) {
      instance.backgroundImage(this.customImage);
      instance.backgroundImageSize(ImageSize.Cover);
     } else {
      instance.backgroundColor(DEFAULT_BACKGROUND_COLOR);
      instance.justifyContent(FlexAlign.Center);
      // instance.padding(2)
      // instance.margin(2)
      // instance.opacity(1)
      // instance.clip(false)
      // instance.layoutWeight(1)
      // instance.backgroundBlurStyle(BlurStyle.NONE)
      // instance.alignItems(VerticalAlign.Center)
      // instance.borderWidth(1)
      // instance.borderColor(Color.Pink)
      // instance.borderStyle(BorderStyle.Solid)
      // instance.expandSafeArea([SafeAreaType.SYSTEM])
      // instance.rotate({ angle: 5 })
      // instance.responseRegion({x: 0})
      //instance.mouseResponseRegion({x: 0})
      // instance.constraintSize({minWidth: 25})
      // instance.hitTestBehavior(HitTestMode.Default)
      //instance.backgroundImagePosition(Alignment.Center)
      //instance.foregroundBlurStyle(BlurStyle.NONE)
    }
    instance.size({ width: 50, height: 50 });
    instance.borderRadius(25);
  }
}

@Component
struct Avatar {
  @ObjectLink user: User;

  build() {
    Row() {
      if (!this.user.avatarImage) {
        Text(this.user.name.charAt(0))
          .fontSize(28)
          .fontColor(Color.White)
          .fontWeight(FontWeight.Bold)
      }
    }
    // 3.将自定义RowModifier类作为参数传入,实现按需注册属性
    .attributeModifier(RowModifier.getInstance().setCustomImage(this.user.avatarImage))
  }
}

精简节点数

移除冗余的节点,可能会在Row容器包含一个Row容器。如下代码,Row容器Row容器,这种嵌套实际是多余的,并且会给布局层次结构造成不必要的开销。

scss 复制代码
Row() {
  Row(){
    Image()
    Text()
  }
  Image()
}

修改后的代码

scss 复制代码
Row() {
  Image()
  Text()
  Image()
}

合理使用布局容器组件

  • 在相同嵌套层级的情况下,如果多种布局方式可以实现相同布局效果,优选低耗时的布局,如使用Column、Row替代Flex实现相同的单行布局。
  • 在能够通过其他布局大幅优化节点数的情况下,可以使用高级组件替代,如使用RelativeContainer替代Row、Column实现扁平化布局,此时其收益大于布局组件本身的性能差距。
  • 仅在必要的场景下使用高耗时的布局组件,如使用Flex实现折行布局、使用Grid实现二维网格布局等。

利用布局边界减少布局计算

如果组件的宽高不需要自适应,那就写死宽高。当其组件外部的容器尺寸发生变化时,组件本身的宽高固定,就不需要重新测量。

合理控制元素显示与隐藏

使用Visibility.None、if条件判断等都能够元素显示与隐藏。如果频繁修改元素的显示与隐藏,通过visibility属性控制,可以省去组件创建的时间,直接进入渲染过程。交互次数很少的情况下,使用if条件判断来控制元素的显示与隐藏效果,对于内存有较大提升。

Scroll嵌套List场景下,给定List组件宽高

Scroll嵌套List时:

  • 给list组件设置宽高,只有布局区域内的子组件会参与布局。不设置宽高,所有子组件都会参与布局。
  • List使用ForEach加载子组件时,无论是否设置List的宽高,都会加载所有子组件。
  • List使用LazyForEach加载子组件时,没有设置List的宽高,会加载所有子组件,设置了List的宽高,会加载List显示区域内的子组件。

优先使用组件属性代替嵌套组件

在实现文本浮层、按压遮罩或颜色叠加等场景时,通常会采用Stack布局嵌套组件的方式。实际上有些场景直接使用组件属性或借助系统API的能力就能实现,例如使用overlay属性可以实现浮层场景,使用ColorMetrics可以实现颜色叠加效果。直接使用组件属性可以减少Stack布局嵌套组件,减少组件节点数。

相关推荐
鸿蒙自习室3 小时前
鸿蒙多线程开发——线程间数据通信对象02
ui·harmonyos·鸿蒙
无尽的大道5 小时前
深入理解 Java 阻塞队列:使用场景、原理与性能优化
java·开发语言·性能优化
loey_ln5 小时前
webpack配置和打包性能优化
前端·webpack·性能优化
SuperHeroWu75 小时前
【HarmonyOS】鸿蒙应用接入微博分享
华为·harmonyos·鸿蒙·微博·微博分享·微博sdk集成·sdk集成
zhangjr05758 小时前
【HarmonyOS Next】鸿蒙实用装饰器一览(一)
前端·harmonyos·arkts
诗歌难吟46415 小时前
初识ArkUI
harmonyos
SameX15 小时前
HarmonyOS Next 设备安全特性深度剖析学习
harmonyos
郭梧悠16 小时前
HarmonyOS(57) UI性能优化
ui·性能优化·harmonyos
奈斯ing16 小时前
【Oracle篇】SQL性能优化实战案例(从15秒优化到0.08秒)(第七篇,总共七篇)
运维·数据库·sql·oracle·性能优化
郝晨妤1 天前
鸿蒙原生应用开发元服务 元服务是什么?和App的关系?(保姆级步骤)
android·ios·华为od·华为·华为云·harmonyos·鸿蒙