HarmonyOS鸿蒙Next中由AttributeModifier引发的奇怪的GC问题

HarmonyOS鸿蒙Next中由AttributeModifier引发的奇怪的GC问题

class HShaderStyleModifier implements AttributeModifier<TextAttribute>{
  colorTheme: Array<[string, number]> = [['#ff32d043', 0.0], ['#ffff4136', 1]]

  applyNormalAttribute(instance: TextAttribute): void {
    console.debug(`调试:字体色彩渐变`)
    instance.shaderStyle({
      direction: GradientDirection.Right,
      colors: this.colorTheme
    })
    console.debug(`调试:字体色彩渐变完成`)
  }
  constructor(colorTheme: Array<[string, number]>) {
    console.debug(`调试:调用构造函数`)
    this.colorTheme = colorTheme//去掉这一句也会正常显示
  }
}

@Entry
@Component
struct Login {
  @State appTitle: Resource | string = '114514';

  @State colorTheme: Array<[string, number]> =[['#ff32d043', 0.0], ['#ffff4136', 1]]
  shaderStyleModifier = new HShaderStyleModifier(this.colorTheme)

  build() {
    Column({space : '20%'}) {
      Text(this.appTitle)
        .attributeModifier(this.shaderStyleModifier)//去掉这一句就会正常显示
    }
  }
}

这样的一份页面代码会触发奇怪的GC问题,相关错误日志贴在下面了。

sdkAPIVersion: 21

毕竟shaderStyle是API21才有的。

补充:colorTheme再封装一维数组程序就又可以了:

colorTheme: Array<[string, number]> = [[[’#ff32d043’, 0.0], [’#ffff4136’, 1]]]


更多关于HarmonyOS鸿蒙Next中由AttributeModifier引发的奇怪的GC问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

8 回复

【解决方案】

参考官网文档getTarget接口:状态管理框架会对class、Date、Map、Set、Array类型的原始对象添加代理,用于观测属性变化与API调用。这一层代理会使得变量类型改变,在类型判断、NAPI调用等场景,会由于类型并非原始对象的类型产生预料之外的结果。 建议使用UIUtils.getTarget接口获取代理前的原始对象。 示例代码如下:

import { UIUtils } from '@kit.ArkUI';
class HShaderStyleModifier implements AttributeModifier<TextAttribute>{
  colorTheme: Array<[string, number]> = [['#ff32d043', 0.0], ['#ffff4136', 1]]

  applyNormalAttribute(instance: TextAttribute): void {
    console.debug(`调试:字体色彩渐变`)
    instance.shaderStyle({
      direction: GradientDirection.Right,
      colors: this.colorTheme
    })
    console.debug(`调试:字体色彩渐变完成`)
  }
  constructor(colorTheme: Array<[string, number]>) {
    console.debug(`调试:调用构造函数`)
    this.colorTheme = colorTheme//去掉这一句也会正常显示
  }
}

@Entry
@Component
struct Login {
  @State appTitle: Resource | string = '114514';

  @State colorTheme: Array<[string, number]> =[['#ff32d043', 0.0], ['#ffff4136', 1]]
  shaderStyleModifier = new HShaderStyleModifier(UIUtils.getTarget(this.colorTheme))

  build() {
    Column({space : '20%'}) {
      Text(this.appTitle)
        .attributeModifier(this.shaderStyleModifier)//去掉这一句就会正常显示
    }
  }
}

更多关于HarmonyOS鸿蒙Next中由AttributeModifier引发的奇怪的GC问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


十分感谢!这个方法是可用的!

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

this.colorTheme = UIUtils.getTarget(colorTheme)

由于UIUtils.getTarget接口获取的是原始对象,所以如果想要更新UI,单纯更新colorTheme是无法刷新UI的,可以定义为如下格式

class HShaderStyleModifier implements AttributeModifier<TextAttribute> {
  private getColors: () => Array<[string, number]>

  constructor(getColors: () => Array<[string, number]>) {
    this.getColors = getColors
  }

  applyNormalAttribute(instance: TextAttribute): void {
    const rawColors = UIUtils.getTarget(this.getColors())

    instance.shaderStyle({
      direction: GradientDirection.Right,
      colors: rawColors
    })
  }
}

补充:简单的colorTheme封装是不行的,也许是关于拷贝了@State的状态导致的。

目前的可行解法:

constructor(colorTheme: Array<[string, number]>) {
  this.colorTheme[0] = colorTheme[0]
  this.colorTheme[1] = colorTheme[1]
}

但是还是没有从根本上解决这个问题

在HarmonyOS Next中,AttributeModifier可能导致GC异常,因为其内部持有对UI组件的引用,若未及时释放,会延长组件生命周期,引发内存泄漏。GC频繁触发或延迟回收,通常与AttributeModifier未正确解绑有关。需检查AttributeModifier的使用,确保在组件销毁时解除绑定,避免循环引用。

从你提供的代码和日志来看,这个GC问题很可能与HarmonyOS Next中AttributeModifier的生命周期管理以及ArkTS/ArkUI的渲染机制有关。

核心问题分析:

  1. AttributeModifier的持有与重建:在你的代码中,shaderStyleModifierLogin组件的一个成员变量。当Text组件应用了.attributeModifier(this.shaderStyleModifier)后,UI框架内部很可能会持有对该AttributeModifier实例的引用,以便在需要时(如重建、更新时)调用其applyNormalAttribute方法。

  2. 状态更新与组件重建Login组件使用了@State装饰器。当appTitlecolorTheme状态发生变化时,Login组件的build方法会被重新执行。但是,shaderStyleModifier = new HShaderStyleModifier(this.colorTheme)这一行是在组件构建时(更准确地说,是在实例化时)执行的,它并不是在build函数内。 这意味着,除非组件实例被完全销毁并重新创建,否则shaderStyleModifier指向的始终是同一个HShaderStyleModifier实例。

  3. 潜在的循环引用或无效引用:问题可能出现在UI框架内部对AttributeModifier的管理上。当Text组件关联了AttributeModifier后,框架可能建立了一个从渲染树到你的HShaderStyleModifier实例的引用。在某些情况下(可能与特定的渲染流程、GC触发时机有关),这个引用关系可能没有被正确清理,或者导致了无法被GC正确识别的引用环。你提到的“去掉.attributeModifier(this.shaderStyleModifier)这一句就会正常显示”,这直接证明了问题与attributeModifier的使用强相关。

  4. 数组结构的影响:你提到将colorTheme封装成三维数组后问题消失。这暗示了**AttributeModifier内部可能对传入的数据(特别是作为参数传递给API如shaderStyle的数据)有特定的结构或生命周期期望**。使用不同的数据结构可能意外地避免了触发框架内部某个有缺陷的引用路径或序列化/反序列化逻辑。

直接原因推断: 最可能的情况是,在API 21的当前实现中,AttributeModifier与使用shaderStyle等图形相关API的组合,在特定数据格式下,会引发UI框架底层(可能是Native层)在管理相关渲染资源时产生一个临时性的无效内存引用或循环引用。当GC运行时,这个无效引用导致其尝试访问或清理一个非法内存地址,从而抛出访问违规(Access Violation)或类似错误,最终表现为你看到的“奇怪的GC问题”。

建议的解决方案:

  1. 优先使用三维数组格式:既然你已验证Array<[string, number]>格式(即[[['#ff32d043', 0.0], ['#ffff4136', 1]]])可以正常工作,这是一个有效的规避方案。确保传递给shaderStylecolors参数符合其API文档期望的格式。

  2. 考虑在build内或使用@Builder创建Modifier:如果后续发现其他问题,可以尝试将AttributeModifier的创建移到build函数内或一个用@Builder装饰的函数中。但这需要谨慎,因为可能会影响性能或导致不必要的重复创建。目前你的单例模式在大多数情况下是合理的。

  3. 关注SDK更新:此类问题通常与特定API版本的底层实现有关。关注HarmonyOS SDK的后续更新日志,看是否有对AttributeModifier或图形渲染相关GC行为的修复。

当前,使用三维数组格式是明确可行的解决方案。这很可能是当前SDK版本中shaderStyle API与AttributeModifier结合时,对输入数据格式处理的一个边界情况或缺陷。

回到顶部