HarmonyOS Next中使用分帧渲染优化下面代码?

@Component
export struct ProductList {
  private productData: ProductDataSource = new ProductDataSource();

  aboutToAppear() {
    this.productData.pushData(PRODUCT_DATA);
  }

  build() {
    WaterFlow() {
      LazyForEach(this.productData, (item: ProductDataModel) => {
        FlowItem() {
          // ...
        }
      }, (item: ProductDataModel) => item.id.toString())
    }
    // ...
  }
}

本文参与了 【 HarmonyOS NEXT 技术问答冲榜,等你来战!】欢迎正在阅读的你也加入。

阅读 589
avatarAI BotBETA
在HarmonyOS Next中,使用分帧渲染(Frame Rendering)优化代码的关键在于将繁重的渲染任务分散到多个帧中执行,以减少单次渲染的负载,从而提高应用的性能和流畅度。针对你提供的代码,可以考虑以下优化策略:

1. **延迟数据加载**:
   在`aboutToAppear`方法中,不要立即推送所有数据,而是可以分批推送,或者先推送部分数据,然后根据用户的滚动行为动态加载更多数据。

2. **使用虚拟列表**:
   对于大量数据的渲染,虚拟列表(Virtual List)是一个有效的优化手段。它只渲染当前可见区域的数据项,对未显示的数据项进行懒加载或回收,从而大大减少渲染的DOM节点数量。

3. **分帧渲染实现**:
   虽然HarmonyOS本身没有直接提供分帧渲染的API,但你可以通过异步任务或定时器来模拟分帧渲染的效果。例如,可以将数据分批处理,并在每帧的空闲时间中逐步渲染。

下面是一个简化的示例,展示了如何通过异步任务模拟分帧渲染(注意:这只是一个概念性的示例,具体实现可能需要根据实际情况调整):

@Component
export struct ProductList {
private productData: ProductDataSource = new ProductDataSource();
private pendingData: ProductDataModel[] = PRODUCT_DATA.slice(); // 剩余待渲染的数据

aboutToAppear() {

this.loadDataInFrames();

}

private async loadDataInFrames() {

while (this.pendingData.length > 0) {
  // 每次只推送一部分数据,例如10个
  const batchSize = 10;
  const batch = this.pendingData.splice(0, batchSize);
  this.productData.pushData(batch);

  // 等待下一帧(模拟)
  await new Promise(requestAnimationFrame);

  // 注意:这里的requestAnimationFrame并不是HarmonyOS的API,
  // 只是一个示意性的函数,表示等待浏览器或系统的下一帧渲染。
  // 在HarmonyOS中,你可能需要使用其他机制来实现类似的等待效果。
}

}

build() {

WaterFlow() {
  LazyForEach(this.productData, (item: ProductDataModel) => {
    FlowItem() {
      // ...
    }
  }, (item: ProductDataModel) => item.id.toString())
}
// ...

}
}

// 注意:上面的requestAnimationFrame是一个浏览器API,用于在下一个重绘之前调用指定的回调函数。
// 在HarmonyOS中,你需要找到相应的API或机制来实现类似的等待效果。
// 例如,你可以使用setTimeout或自定义的帧管理逻辑来模拟这一行为。


**注意**:上述代码中的`requestAnimationFrame`并非HarmonyOS API,而是一个浏览器API。在HarmonyOS开发中,你需要寻找或实现一个等效的机制来等待下一帧。这通常涉及到对系统渲染循环的理解和对异步编程的熟练掌握。

此外,具体的优化策略还需要根据你的应用场景、数据量和性能瓶颈进行调整。在实际开发中,建议使用性能分析工具(如HarmonyOS提供的性能监控工具)来识别性能瓶颈,并针对性地进行优化。
1 个回答

这段代码里,在组件即将出现时回调aboutToAppear()接口,将数据放入productData中,并通过瀑布流加载。编译运行后,可以通过Trace图看到,转场动画的首帧耗时21ms左右,这是因为在点击进入页面时将数据全部放入瀑布流,在235970帧中需要计算每个子组件的尺寸,导致了响应时间增长。
在aboutToAppear()接口中添加displaySync的帧回调,并将数据拆分进行加载。

@Component
export struct ProductList {
  private productData: ProductDataSource = new ProductDataSource();
  private displaySync: displaySync.DisplaySync | undefined = undefined;
  private frame: number = 1;

  aboutToAppear(): void {
    // 创建DisplaySync对象
    this.displaySync = displaySync.create();
    // 设置期望帧率
    const range: ExpectedFrameRateRange = {
      expected: 120,
      min: 60,
      max: 120
    };
    this.displaySync.setExpectedFrameRateRange(range);
    // 添加帧回调
    this.displaySync.on('frame', () => {
      if (this.frame === 1) {
        hiTraceMeter.startTrace('firstFrame', 1);
        this.productData.pushData(PRODUCT_DATA.slice(0, 2))
        this.frame += 1;
        hiTraceMeter.finishTrace('firstFrame', 1);
      } else if (this.frame === 2) {
        hiTraceMeter.startTrace('secondFrame', 2);
        this.productData.pushData(PRODUCT_DATA.slice(2, PRODUCT_DATA.length));
        hiTraceMeter.finishTrace('secondFrame', 2);
        this.frame += 1;
        this.displaySync?.stop();
      }
    });
    // 开启帧回调监听
    this.displaySync.start();
  }

  aboutToDisappear(): void {
    // 页面销毁时需要停止帧回调
    this.displaySync?.stop();
  }

  build() {
    WaterFlow() {
      LazyForEach(this.productData, (item: ProductDataModel) => {
        FlowItem() {
          // ...
        }
      }, (item: ProductDataModel) => item.id.toString())
    }
    // ...
  }
}

本文参与了 【 HarmonyOS NEXT 技术问答冲榜,等你来战!】欢迎正在阅读的你也加入。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题