HarmonyOS鸿蒙NEXT关于页面渲染的性能优化方案
HarmonyOS鸿蒙NEXT关于页面渲染的性能优化方案
HarmonyOS Next 关于页面渲染的性能优化方案
页面渲染过程
HarmonyOS Next 应用开发中,用户的使用体验至关重要。其中用户启动APP到呈现页面主要包含三个步骤:
- 框架初始化
- 页面加载
- 布局渲染
从页面加载到布局渲染中,主要包含了6个环节:
- 执行页面文件
- 生成页面节点树
- 页面节点树挂载
- 布局
- 渲染
- 展示
页面节点树挂载的速度取决于节点的数量,我们可以理解给1个自定义组件在渲染时,后端同时会生成一个对应的节点。该节点后期会用来diff。
渲染的速度取决于布局属性。如果布局属性越复杂、冗余。那么就越慢。
节点的数量优化
HarmonyOS Next 会根据自定义节点的数量在后端生成对应的节点。那么如果我们在实际开发中,可以考虑尽量的将自定义组件的数量减少,替换成 @Builder
自定义构建函数。
那么哪些自定义节点可以替换成 @Builder
自定义构建函数呢,看下表:
分类 | 自定义组件 | @Builder |
---|---|---|
复用布局结构 | 支持 | 支持 |
复用样式 | 支持 | 支持 |
导出使用 | 支持 | 不支持 |
生命周期 | 支持 | 不支持 |
状态管理 | 支持 | 不支持 |
所以,当我们对于封装的需求,不需要导出使用、不需要使用生命周期、不需要独立的状态管理时。就可以使用 @Builder
来代替自定义组件。
@Builder
的基本使用
@Component
struct 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)
}
}
自定义组件的基本使用
@Component
struct CustomBtn {
text: string = ""
build(){
Button(this.text)
.width(100)
.height(50)
.linearGradient({
colors: [[Color.Black, 0], [Color.Red, 1]]
})
}
}
@Component
struct Index {
build(){
Column({ space: 10 }) {
CustomBtn({text:"登录"})
CustomBtn({text:"注册"})
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
}
}
布局属性的优化
这里的优化,主要是指性能的优化,也就是用户体验的优化,不是对于开发者来讲的开发体验的优化。
HarmonyOS Next 有提供 @Styles
和 @Extends
来实现代码层面的优化,也就是样式代码的简单封装。
但是无论是用户层面的优化和代码层面的优化。@Styles
和 @Extends
都存在一定的限制。因此HarmonyOS Next 又推出了 AttributeModifier
和 AttributeUpdater
(AttributeUpdater 是AttributeModifier的继承)。
AttributeModifier
AttributeModifier
是一个接口,需要我们主动实现它相关的方法。如默认态(Normal)、按压态(Pressed)、焦点态(Focused)、禁用态(Disabled)、选择态(Selected)AttributeModifier
可以实现样式属性的按需注册- 支持和
@Observed
和@ObjectLink
配套使用
AttributeModifier 基本使用
export class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
isDark: boolean = false
constructor(dark?: boolean) {
this.isDark = !!dark
}
applyNormalAttribute(instance: ButtonAttribute): void {
if (this.isDark) {
instance.backgroundColor(Color.Black)
.fontColor(Color.White)
.border({
width:10,
color:Color.Brown
})
.borderRadius(20)
.padding(10)
.margin(20)
} else {
instance.backgroundColor(Color.White)
.fontColor(Color.Black)
}
}
}
@Component
struct attributeDemo {
@State modifier: MyButtonModifier = new MyButtonModifier(false);
build(){
Row() {
Column() {
Button("Button")
// 注册属性
.attributeModifier(this.modifier)
.onClick(() => {
// 点击切换
this.modifier.isDark = !this.modifier.isDark
})
}
.width('100%')
}
.height('100%')
}
}
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
对象嵌套对象
// 定义一个名为 'BtnModifier' 的类,实现对 'ButtonAttribute' 的属性修改
class BtnModifier implements AttributeModifier<ButtonAttribute> {
son: Son;
constructor(son: Son) {
this.son = son;
}
applyNormalAttribute(instance: ButtonAttribute): void {
if (this.son.isShow) {
instance.backgroundColor(Color.Red);
} else {
instance.backgroundColor(Color.Green);
}
}
}
@Observed
class Son {
// 控制样式切换的关键变量
isShow: boolean = false;
}
@Observed
class Person {
son: Son = new Son();
}
@Component
struct CustomBtn {
@ObjectLink
son: Son;
modify: BtnModifier | null = null;
aboutToAppear(): void {
this.modify = new BtnModifier(this.son);
}
build(){
Button(this.son.isShow.toString())
// 设置按钮的属性修改器为 'modify'
.attributeModifier(this.modify);
}
}
@Component
struct Index {
@State
person: Person = new Person();
build(){
Column() {
// 创建一个自定义按钮组件,并传入 'person.son' 作为参数
CustomBtn({ son: this.person.son })
// 为按钮添加点击事件处理函数
.onClick(() => {
// 切换 'person.son.isShow' 的值
this.person.son.isShow = !this.person.son.isShow;
// 显示一个提示信息
promptAction.showToast({ message: `${this.person.son.isShow}` });
});
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center);
}
}
数组嵌套对象
// 定义一个名为 'BtnModifier' 的类,实现对 'ButtonAttribute' 的属性修改
class BtnModifier implements AttributeModifier<ButtonAttribute> {
static instance: BtnModifier;
isTalk: boolean = false;
static getInstance(): BtnModifier {
if (!BtnModifier.instance) {
BtnModifier.instance = new BtnModifier();
}
return BtnModifier.instance;
}
setTalk(isTalk: boolean): BtnModifier {
this.isTalk = isTalk;
return this;
}
applyNormalAttribute(instance: ButtonAttribute): void {
if (this.isTalk) {
instance.backgroundColor(Color.Red);
} else {
instance.backgroundColor(Color.Green);
}
}
}
@Observed
class Person {
userName: string = "人类";
isTalk: boolean = false;
}
@Component
struct CustomBtn {
@ObjectLink
person: Person;
modify: BtnModifier = BtnModifier.getInstance();
build(){
Button(person.userName)
// 设置按钮的属性修改器,并根据 'person.isTalk' 的值设置是否在交谈状态
.attributeModifier(modify.setTalk(person.isTalk));
}
}
@Component
struct Index {
@State
personList: Person[] = [new Person(), new Person()];
build(){
Column() {
ForEach(this.personList, (person: Person) => {
CustomBtn({ person })
.onClick(() => {
// 切换 'person.isTalk' 的值
person.isTalk = !person.isTalk;
});
});
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center);
}
}
AttributeModifier 和 @Styles
、@Extend
的比较
能力 | @Styles |
@Extend |
AttributeModifier |
---|---|---|---|
跨文件导出 | 不支持 | 不支持 | 支持 |
通用属性设置 | 支持 | 支持 | 支持 |
通用事件设置 | 支持 | 支持 | 部分支持 |
组件特有属性设置 | 不支持 | 支持 | 部分支持 |
组件特有事件设置 | 不支持 | 支持 | 部分支持 |
参数传递 | 不支持 | 支持 | 支持 |
多态样式 | 支持 | 不支持 | 支持 |
业务逻辑 | 不支持 | 不支持 | 支持 |
基于以上对比,可以看见 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
基本能力,还拓展了直接修改属性和组件构造函数的能力。用来根据单一状态来批量修改样式属性。
简单实用
- 声明
MyButtonUpdater
类,继承AttributeUpdater
- 组件中实例化
MyButtonUpdater
类 - 直接修改组件样式属性
import { AttributeUpdater } from '@kit.ArkUI';
// 注意,这里是继承 AttributeUpdater 类
class MyButtonUpdater extends AttributeUpdater<ButtonAttribute> {
}
@Component
struct 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
接口,可以让我们重新调用该组件的构造函数。实现组件的重新渲染
- 继承
AttributeUpdater
类时,同时传入两个泛型ButtonAttribute
和ButtonInterface
class MyButtonUpdater extends AttributeUpdater<ButtonAttribute,ButtonInterface> {
}
- 直接调用要组件的构造函数
updateConstructorParams
import { AttributeUpdater } from '@kit.ArkUI';
// 注意,这里是继承 AttributeUpdater 类
class MyButtonUpdater extends AttributeUpdater<ButtonAttribute,ButtonInterface> {
}
@Component
struct attributeDemo {
@State modifier: MyButtonUpdater = new MyButtonUpdater();
build(){
Row() {
Column() {
Button("重新渲染组件")
.attributeModifier(this.modifier)
.onClick(() => {
this.modifier.updateConstructorParams("文本也可以改变")
})
}
.width('100%')
}
.height('100%')
}
}
接口定义
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
更多关于HarmonyOS鸿蒙NEXT关于页面渲染的性能优化方案的实战教程也可以访问 https://www.itying.com/category-93-b0.html
后期如果要考虑实现样式复用,可以优先使用 AttributeModifier 和 AttributeUpdater。
更多关于HarmonyOS鸿蒙NEXT关于页面渲染的性能优化方案的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙NEXT中,页面渲染的性能优化主要从以下几个方面进行:
-
UI组件优化:使用轻量级UI组件,避免过度嵌套和复杂的布局结构。减少不必要的组件刷新,通过
@State
、@Prop
等装饰器实现局部更新。 -
布局优化:采用高效的布局方式,如
Flex
布局,避免使用AbsoluteLayout
等性能开销较大的布局。合理使用Visibility
属性,减少不可见组件的渲染开销。 -
列表优化:在长列表渲染中,使用
LazyForEach
或List
组件的reuse
机制,减少内存占用和渲染时间。通过onAppear
和onDisappear
事件管理列表项的加载和卸载。 -
动画优化:使用
Animation
组件和Transition
组件实现高效动画,避免使用setInterval
或setTimeout
等JavaScript定时器触发动画。 -
资源优化:压缩图片资源,使用
WebP
格式替代PNG
或JPEG
,减少内存占用。合理管理资源加载,避免一次性加载过多资源。 -
线程优化:将耗时操作放在
Worker
线程中执行,避免阻塞UI主线程。使用TaskPool
进行多任务并行处理,提升整体性能。 -
事件优化:减少事件绑定的数量,使用事件委托机制,避免频繁触发事件回调。
-
缓存优化:利用
Storage
或Preferences
进行数据缓存,减少重复数据请求和渲染。
通过以上优化方案,可以有效提升HarmonyOS鸿蒙NEXT页面渲染的性能,确保流畅的用户体验。
在HarmonyOS鸿蒙NEXT中,页面渲染性能优化可从以下方面入手:
- 减少布局层级:使用扁平化布局,减少嵌套,提升渲染速度。
- 重用组件:通过
RecyclerView
或ListContainer
等组件重用机制,减少内存占用。 - 异步加载:将耗时操作(如网络请求、图片加载)放在后台线程,避免阻塞UI线程。
- 硬件加速:启用硬件加速,提升图形渲染效率。
- 资源优化:压缩图片、使用矢量图,减少资源加载时间。
- 避免过度绘制:使用
Canvas.clipRect()
等方法,减少不必要的绘制操作。
通过这些策略,可显著提升页面渲染性能,优化用户体验。