DEV Community

陈杨
陈杨

Posted on

Hong Mong 5 Development Treasure Case Sharing Waterfall Stream Optimization Real Battle Sharing

Below is an unofficial technical sharing based on the official HarmonyOS waterfall flow optimization case, reinterpreted with practical development experience, and enriched with more scenario analysis and code examples:


🌟 HarmonyOS Waterfall Flow Performance Optimization in Practice: Say Goodbye to Lag with This Treasure Guide!

Hello everyone! Recently, I discovered a performance optimization treasure trove in the HarmonyOS documentation. It turns out that the official team has already prepared best practices for various scenarios! Today, I'll focus on sharing the solution for "waterfall flow slow loading and dropped frames," complete with full code analysis and lessons learned from real-world pitfalls.


1. Why Is the Waterfall Flow Prone to Lag?

// Typical problematic code example
WaterFlow() {
  ForEach(this.data, (item) => { // ❌ No lazy loading
    FlowItem() {
      ComplexComponent(item) // Complex subcomponent
    }
    .height('auto') // ❌ Height not fixed
  })
}
Enter fullscreen mode Exit fullscreen mode

Three Major Performance Killers:

  1. One-time rendering: ForEach loads all data at once
  2. Dynamic height: Image loading triggers re-layout
  3. Component reconstruction: Components are repeatedly created and destroyed during scrolling

2. Four Official Optimization Solutions (with Practical Code)

Solution 1: Lazy Loading + Cache Pool

WaterFlow() {
  LazyForEach(this.dataSource, (item) => {
    FlowItem() {
      ReusableComponent(item) // ✅ Reusable component
    }
    .height(this.calcHeight(item)) // ✅ Fixed height
  }, item => item.id)
}
.columnsTemplate("1fr 1fr")
.cachedCount(5) // ✅ Cache 5 items off-screen
Enter fullscreen mode Exit fullscreen mode

Optimization Principle:

  • LazyForEach: Only renders components in the viewport
  • cachedCount: Builds a scroll buffer (similar to RecyclerView's cache pool)

Solution 2: Component Reuse (Key!)

@Reusable // ✅ Magic decorator
@Component
struct ReusableComponent {
  build() {
    // Avoid creating temporary components inside
    Column() {
      OptimizedImage() // Optimized image component
      Text(...).lineClamp(2) // Limit text lines
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Reuse Level Recommendations:

  1. Reuse basic blocks like image + text
  2. Reuse the entire card (requires fixed height)

Solution 3: Dynamic Preloading

.onScrollIndex((first, last) => {
  if (last >= totalData - 10) { // ✅ Load when 10 items from the bottom
    loadMoreData() 
  }
})
Enter fullscreen mode Exit fullscreen mode

Smoother than **`onReachEnd*`:*

Preload data in advance to avoid the "white screen pause" while users wait

Solution 4: Fixed Height Calculation (Core Technique)

// Pre-calculate image height
private calcHeight(item: ItemData): number {
  const imgRatio = item.imgHeight / item.imgWidth
  const cardWidth = (deviceWidth - gaps) / columns
  return cardWidth * imgRatio + titleHeight + padding
}
Enter fullscreen mode Exit fullscreen mode

Avoid Layout Jitter:

When images load asynchronously, the height won't stretch the container


3. Performance Comparison Test (500 Data Items)

Optimization Solution Memory Usage First Render Scroll FPS
Unoptimized 485MB 1346ms 45fps
Lazy Loading 122MB 756ms 58fps
+Cache+Reuse 103MB 761ms 59fps
+Fixed Height 98MB 623ms 60fps

💡 Fixed height reduces layout calculation by about 40%


4. Pitfall Guide (Lessons Learned)

  1. Image Optimization:
Image(item.url)
  .objectFit(ImageFit.Contain) // Avoid the calculation overhead of Cover
  .syncLoad(true) // Use synchronous loading for small images
Enter fullscreen mode Exit fullscreen mode
  1. Avoid Deep Nesting:
// ❌ Wrong example: 3 layers of Column + 2 layers of Stack
// ✅ Recommended: Flatten layout, use RelativeContainer
Enter fullscreen mode Exit fullscreen mode
  1. Special Handling for Video Cards:
.onAppear(() => playVideo())
.onDisappear(() => stopVideo()) // Must release in time!
Enter fullscreen mode Exit fullscreen mode

Conclusion

I didn't expect so many practical cases to be hidden in the HarmonyOS documentation! After this optimization, our waterfall flow FPS stabilized at 58+, and memory usage dropped by 70%.

What other performance bottlenecks have you encountered? Feel free to discuss and share in the comments below👇

Top comments (0)