写点什么

HarmonyOS Next 关于页面渲染的性能优化方案

作者:万少
  • 2024-12-15
    江苏
  • 本文字数:4038 字

    阅读完需:约 13 分钟

HarmonyOS Next 关于页面渲染的性能优化方案

HarmonyOS Next 关于页面渲染的性能优化方案

HarmonyOS Next 应用开发中,用户的使用体验至关重要。其中用户启动 APP 到呈现页面主要包含三个步骤:


  1. 框架初始化

  2. 页面加载

  3. 布局渲染



页面加载布局渲染中,主要包含了 6 个环节:


  1. 执行页面文件

  2. 生成页面节点树

  3. 页面节点树挂载

  4. 布局

  5. 渲染

  6. 展示


页面节点树挂载的速度取决于节点的数量,我们可以理解给 1 个自定义组件在渲染时,后端同时会生成一个对应的


节点。该节点后期会用来 diff


渲染的速度取决于布局属性。如果布局属性越复杂、冗余。那么就越慢。

节点的数量优化

HarmonyOS Next 会根据自定义节点的数量在后端生成对应的节点。那么如果我们在实际开发中,可以考虑尽量的将自定义组件的数量减少,替换成 @Builder 自定义构建函数。


那么哪些自定义节点可以替换成**@Builder**自定义构建函数呢,看下表:



所以,当我们对于封装的需求,不需要导出使用、不需要使用生命周期、不需要独立的状态管理时。就可以使用**@Builder**来代替自定义组件。

@Builder 的基本使用


@Entry@Componentstruct Index {  @Builder  CustomBtn(text:string){    Button(text)      .width(100)      .height(50)      .linearGradient({        colors:[[Color.Black,0],[Color.Red,1]]      })  }
build() { Column({space:10}){ this.CustomBtn("登录") this.CustomBtn("注册")
} .width("100%") .height("100%") .justifyContent(FlexAlign.Center) }}
复制代码

自定义组件的基本使用


@Componentstruct CustomBtn {  text: string = ""
build() { Button(this.text) .width(100) .height(50) .linearGradient({ colors: [[Color.Black, 0], [Color.Red, 1]] }) }}
@Entry@Componentstruct Index { build() { Column({ space: 10 }) { CustomBtn({text:"登录"}) CustomBtn({text:"注册"})
} .width("100%") .height("100%") .justifyContent(FlexAlign.Center) }}
复制代码

布局属性的优化

这里的优化,主要是指性能的优化,也就是用户体验的优化,不是对于开发者来讲的开发体验的优化。


HarmonyOS Next 有提供 @Styles@Extends 来实现代码层面的优化,也就是样式代码的简单封装。


但是无论是用户层面的优化和代码层面的优化。**@Styles** 和 @Extends 都存在一定的限制。因此 HarmonyOS


Next 又推出了 AttributeModifierAttributeUpdater(AttributeUpdater 是 AttributeModifier 的继承 )

AttributeModifier

  1. AttributeModifier 是一个接口,需要我们主动实现它相关的方法。如默认态(Normal)、按压态(Pressed)、焦点态(Focused)、禁用态(Disabled)、选择态(Selected)

  2. AttributeModifier 可以实现样式属性的按需注册

  3. 支持和 @Observed 和 @ObjectLink 配套使用

AttributeModifier 基本使用

  1. 定义 MyButtonModifier 类,继承 AttributeModifier 接口,并且声明是对 Button 进行的样式属性封装

  2. MyButtonModifier 中声明变量,用来注册不同的样式属性

  3. 定义正常态的样式 (applyNormalAttribute 是接口 AttributeModifier 中定义的 )


  4. 组件中开始复用(完整代码)

  5. 效果


AttributeModifier 其他状态

多态样式中除了默认态(Normal)还有 、按压态(Pressed)、焦点态(Focused)、禁用态(Disabled)、选择态(Selected)。我们一并实现。


  // 按压  applyPressedAttribute(instance: ButtonAttribute): void {    instance      .backgroundColor(Color.Red)  }  // 获得焦点  applyFocusedAttribute(instance: ButtonAttribute): void {  }  // 选择  applySelectedAttribute(instance: ButtonAttribute): void {  }  // 禁用  applyDisabledAttribute(instance: ButtonAttribute): void {  }
复制代码


搭配 @Observed 和 @ObjectLink

上述案例中,样式的变更是根据 变量 isDark 来实现的。如果想要根据对象中某个属性来实现样式的变更。我们可以搭配 @Observed 和 @ObjectLink

对象嵌套对象

以下代码主要利用了 @Observed 和 @ObjectLink 可以监听深层次属性的改变,然后当深层次属性改变后,触发


AttributeModifier 跟随改变。


  1. 声明子类 Son,代表深层次属性的载体

  2. 使用 @Observed 修饰 Person 类 (父类),拥有 Son 子类

  3. 声明 BtnModifier 类,需要实现 AttributeModifier 接口,实现样式优化和复用。接收 son 属性。用来响应状态变化

  4. 完整代码




数组嵌套对象

数组嵌套对象的写法类似上面示例,但是可以通过简单的一些编程技巧来进一步优化。如单例


// 定义一个名为 'BtnModifier' 的类,实现对 'ButtonAttribute' 的属性修改class BtnModifier implements AttributeModifier<ButtonAttribute> {  // 静态变量,用于存储单例实例  static instance: BtnModifier;  // 表示是否在交谈的布尔属性,初始值为 false  isTalk: boolean = false;
// 静态方法,用于获取单例实例 static getInstance(): BtnModifier { // 如果单例实例不存在,则创建一个新的实例 if (!BtnModifier.instance) { BtnModifier.instance = new BtnModifier(); } // 返回单例实例 return BtnModifier.instance; }
// 设置 isTalk 属性的方法 setTalk(isTalk: boolean): BtnModifier { // 更新 isTalk 属性值 this.isTalk = isTalk; // 返回当前实例,以便进行链式调用 return this; }
// 应用普通属性的方法,接收一个 'ButtonAttribute' 类型的实例作为参数 applyNormalAttribute(instance: ButtonAttribute): void { // 如果 isTalk 为 true,则将按钮背景颜色设置为红色 if (this.isTalk) { instance.backgroundColor(Color.Red); } else { // 否则将按钮背景颜色设置为绿色 instance.backgroundColor(Color.Green); } }}
// 使用 '@Observed' 装饰器标记的类,表示该类的变化可以被观测到@Observedclass Person { // 用户名属性,初始值为 "人类" userName: string = "人类"; // 表示是否在交谈的布尔属性,初始值为 false isTalk: boolean = false;}
@Componentstruct CustomBtn { // 使用 '@ObjectLink' 装饰器标记的属性,表示与外部对象的链接 @ObjectLink person: Person; // 存储 'BtnModifier' 的实例,通过单例模式获取 modify: BtnModifier = BtnModifier.getInstance();
// 构建组件的方法 build() { // 创建一个按钮,并将按钮的文本设置为 'person.userName' Button(this.person.userName)// 设置按钮的属性修改器,并根据 'person.isTalk' 的值设置是否在交谈状态 .attributeModifier(this.modify.setTalk(this.person.isTalk)); }}
@Entry@Componentstruct Index { // 使用 '@State' 装饰器标记的属性,表示该属性的变化会触发组件的重新渲染 @State personList: Person[] = [new Person(), new Person()];
// 构建组件的方法 build() { // 创建一个列容器 Column() { // 遍历 'personList',为每个 'Person' 实例创建一个 'CustomBtn' 组件,并添加点击事件处理函数 ForEach(this.personList, (person: Person) => { CustomBtn({ person: person }) .onClick(() => { // 切换 'person.isTalk' 的值 person.isTalk = !person.isTalk; }); }); } .width("100%") .height("100%") .justifyContent(FlexAlign.Center); }}
复制代码




AttributeModifier 和 @Styles 、@Extend 的比较


基于以上对比,可以看见 AttributeModifier 几乎可以满足以上所有场景。唯一缺点就是代码量稍多一些些。

接口定义

declare interface AttributeModifier<T> {  applyNormalAttribute?(instance: T): void;
applyPressedAttribute?(instance: T): void;
applyFocusedAttribute?(instance: T): void;
applyDisabledAttribute?(instance: T): void;
applySelectedAttribute?(instance: T): void;}
复制代码

AttributeUpdater

如果设计大量的样式属性修改,如果都是基于状态变量,那么在实现修改前,还是会导致 diff 的对比,性能损耗验证。因此引入了 AttributeUpdater,它继承了 AttributeModifier 基本能力,还拓展了直接修改属性和组件构造函数的能力。用来根据单一状态来批量修改样式属性。

简单实用

  1. 声明 MyButtonUpdater 类,继承 AttributeUpdater

  2. 组件中实例化 MyButtonUpdater

  3. 直接修改组件样式属性


import { AttributeUpdater } from '@kit.ArkUI';
// 注意,这里是继承 AttributeUpdater 类class MyButtonUpdater extends AttributeUpdater<ButtonAttribute> {}
@Entry@Componentstruct attributeDemo { @State modifier: MyButtonUpdater = new MyButtonUpdater();
build() { Row() { Column() { Button("直接修改批量样式属性") .attributeModifier(this.modifier) .onClick(() => { // 直接修改 this.modifier.attribute?.backgroundColor(Color.Green).width(200).fontColor(Color.Red) }) } .width('100%') } .height('100%') }}
复制代码




重新调用组件构造函数

提供了updateConstructorParams 接口,可以让我们重新调用该组件的构造函数。实现组件的重新渲染


  1. 继承 AttributeUpdater 类时,同时传入两个泛型 ButtonAttributeButtonInterface

  2. 直接调用要组件的构造函数 updateConstructorParams




接口定义

export declare class AttributeUpdater<T, C = Initializer<T>> implements AttributeModifier<T> {  applyNormalAttribute?(instance: T): void;  initializeModifier(instance: T): void;  get attribute(): T | undefined;  updateConstructorParams: C;}
复制代码

总结

后期如果要考虑实现样式复用,可以优先使用 AttributeModifier 和 AttributeUpdater



发布于: 刚刚阅读数: 5
用户头像

万少

关注

还未添加个人签名 2021-12-02 加入

还未添加个人简介

评论

发布
暂无评论
HarmonyOS Next 关于页面渲染的性能优化方案_鸿蒙_万少_InfoQ写作社区