组件复用提升性能,不小心可能踩的坑,注意避让

组件复用提升性能,不小心可能踩的坑,注意避让

HarmonyOS
2024-06-11 20:45:13
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
Sunny3141

组件复用可以大大提升应用的帧率性能。但是如果使用不小心,可能会引入功能问题。

遇到的问题:组件复用后,应用列表中按钮的状态出现了错乱。比如页面中的按钮状态本来应该是“打开”,因为这个应用已经安装了,但是却显示成了“安装”。

问题分析:

1:问题是出现在组件复用之后,所以怀疑组件复用导致的问题。

2:分析布局结构:应用布局结构是一个NoralCard自定义组件,且是一个复用单元。

并且通过日志观察,应用的组件是复用过的,并且是复用了另外一个未安装的应用。 页面上其他元素如:ICON,应用名称等都是正确,只有按钮状态不符合预期,于是分析代码发现:安装按钮也是应用自定义的一个组件(DownloadButton),也就是DownloadButton是NormalCard的子组件。

3:代码分析:NormalCard中的引用子组件DonwloadButton的代码如下:

export struct NormalCard { 
  @State private cardData: NormalCardData | undefined = undefined; 
  ... 
  Row() { 
    DownloadButton({ 
      inDetailPage: false, 
      appInfo: this.cardData, 
      constraintSizeOptions: this.constraintSizeOptions, 
      fontSize: $r('sys.float.ohos_id_text_size_button3'), 
      fontColor: $r('sys.color.ohos_id_color_text_primary_activated'), 
      defaultBackgroundColor: $r('sys.color.ohos_id_color_button_normal') 
    }) 
  } 
  ... 
} 
 
export struct DownloadButton { 
  ... 
  private appInfo: NormalCardData; 
  ... 
}

如组件复用指导中所提:父组件中cardData增加了状态变量,cardData变化之后,相应的组件会自动刷新。但是由于DownloadButton是自定义组件,DownloadButton接收cardData的变量appInfo是一个普通变量,没有支持父子组件数据传递的状态变量。因此即使父组件中cardData数据变化了,也没有传递给子子组件DownloadButton。

4:修改方案:将子组件DownloadButton中接收父组件数据变化的成员变量:appInfo增加数据同步的状态变量:@Link,同时增减监听事件,变化之后,需要根据appInfo刷新按钮的状态。

export struct DownloadButton { 
  ... 
  @Link @Watch("updateUiWithReuse") appInfo: NormalCardData; 
  ... 
}

5:修改过程中数据同步遇到的问题:一开始考虑业务只需要单向同步:用的@Prop。但是用@Prop之后丢帧更严重中了。通过trace发现。数据同步过程中有大量的数据copy。且由于NormalCardData数据类型嵌套较深,且@Prop是深度copy,导致性能特别差:复用占用了33ms。如下图所示:

6:继续优化:通过与OH 数据同步的同事了解,@Prop是通过数据深度copy完成的数据同步,他们建议如果数据大可以使用@Link进行数据同步,@Link是通过指向同一份地址的方式完成数据同步。修改为@link后,复用效果大大提升。由33MS->2.9MS ,性能有10倍提升。

总结:

1:组件复用要考虑组件中所有元素数据是否都进行了合理的刷新,如果涉及自定义组件,自定义组件涉及的UX变更需要通过数据同步的方式,通知子组件变更,子组件需要根据父组件数据通知的变化,完成本身的UX刷新。

2: 数据同步过程需要根据自己的应用场景选择合适的数据同步状态变量。特别注意@Prob@Link。 @Prop为深度copy的方式,@Link是通过共享数据内存的方式。性能差异较大。

分享
微博
QQ
微信
回复
2024-06-12 17:46:47
相关问题
性能优化中组件复用原理是什么
645浏览 • 1回复 待解决
Swiper是否支持组件复用
369浏览 • 1回复 待解决
复用组件reuseId作用是什么
250浏览 • 1回复 待解决
赋值会导致降低组件复用性能
573浏览 • 1回复 待解决
loaddata api注意事项
449浏览 • 1回复 待解决
Redis Key注意点是什么?
1888浏览 • 1回复 待解决
ArkTS在代码执行效率是如何提升
803浏览 • 1回复 待解决
组件需要多次更新时如何优化性能
781浏览 • 1回复 待解决
如何实现键盘避让机制
1138浏览 • 1回复 待解决
ArkTS静态类型开发时注意事项
956浏览 • 1回复 待解决
学习鸿蒙我们应该注意什么
3940浏览 • 1回复 待解决
List组件性能问题,有人知道吗?
672浏览 • 1回复 待解决
如何实现弹窗和软键盘避让
585浏览 • 1回复 待解决
TairHash相较于Redis Hash提升有哪些?
2104浏览 • 1回复 待解决
组件需要多次更新时,如何优化性能
661浏览 • 1回复 待解决
字体库文件如何复用
2339浏览 • 1回复 待解决
SQL相同两个子查询如何复用
1607浏览 • 2回复 待解决
是否有衡量页面性能 API?
255浏览 • 1回复 待解决