HarmonyOS NEXT 小说阅读器应用系列教程之高性能列表与懒加载技术详解

2025-05-20 20:47:28
127次阅读
0个评论

项目源码地址

项目源码已发布到GitCode平台, 方便开发者进行下载和使用。

https://gitcode.com/qq_33681891/NovelReader

效果演示

11.png

前言

在移动应用开发中,列表性能优化一直是开发者需要重点关注的问题。特别是在电子书阅读等需要流畅翻页体验的场景中,如何高效地加载和渲染内容至关重要。本教程将以小说阅读器应用中的左右翻页功能为例,详细讲解HarmonyOS中的高性能列表实现与懒加载技术。

技术要点

在本教程中,我们将重点介绍以下技术点:

  1. Swiper组件的高效使用
  2. LazyForEach实现按需加载
  3. cachedCount缓存策略
  4. 数据源管理与动态加载

基础架构

首先,让我们了解一下左右翻页功能的基础架构。在HarmonyOS中,我们使用Swiper+LazyForEach+cachedCount的组合来实现高性能的左右翻页效果。

@Component
export struct LeftRightPlipPage {
  @Link isMenuViewVisible: boolean;
  @Link isCommentVisible: boolean;
  @Link currentPageNum: number;
  private swiperController: SwiperController = new SwiperController();
  private data: BasicDataSource = new BasicDataSource([]);
  private screenW: number = px2vp(display.getDefaultDisplaySync().width);
  @Prop bgColor: string;
  @Prop isbgImage: boolean;
  @Prop textSize: number;
  // 播放文章列表
  @Link readInfoList: TextReader.ReadInfo[];
  @Link selectedReadInfo: TextReader.ReadInfo;
  
  // 组件生命周期方法
  aboutToAppear(): void {
    // 初始化数据
    for (let i = CONFIGURATION.PAGEFLIPPAGESTART; i <= CONFIGURATION.PAGEFLIPPAGEEND; i++) {
      this.data.pushItem(STRINGCONFIGURATION.PAGEFLIPRESOURCE + i.toString());
    }
    if (this.screenW > CONFIGURATION.WINDOWWIDTH) {
      this.screenW = this.screenW / 2;
    }
  }
  
  // 构建UI
  build() {
    // 实现UI布局
  }
}

数据源管理

在HarmonyOS中,我们使用BasicDataSource类来管理列表数据。这个类提供了添加、删除和更新数据的方法,是实现高效列表的基础。

数据初始化

在组件的aboutToAppear生命周期方法中,我们初始化数据源:

aboutToAppear(): void {
  /**
   * 请求网络数据之后可以通过this.data.addItem(new Item('app.string.content' + i.toString()));的方法插入到数据源的开头形成新的数据源。
   * 请求网络数据之后可以通过this.data.pushItem(new Item('app.string.content' + i.toString()));的方法插入到数据源的末尾形成新的数据源。
   */
  for (let i = CONFIGURATION.PAGEFLIPPAGESTART; i <= CONFIGURATION.PAGEFLIPPAGEEND; i++) {
    this.data.pushItem(STRINGCONFIGURATION.PAGEFLIPRESOURCE + i.toString());
  }
  if (this.screenW > CONFIGURATION.WINDOWWIDTH) {
    this.screenW = this.screenW / 2;
  }
}

这段代码展示了如何向数据源中添加初始数据。值得注意的是:

  • addItem方法用于在数据源开头添加数据,适合向前加载场景
  • pushItem方法用于在数据源末尾添加数据,适合向后加载场景

动态加载数据

在实际应用中,我们通常需要根据用户的翻页操作动态加载数据。这可以在BasicDataSourcegetData方法中实现:

getData(index: number) {
  // 当index等于0时,向前请求网络数据
  if (index === 0) {
    // 实现向前加载数据的逻辑
    // this.addItem(新数据);
  }
  
  // 当index等于数据源末尾时,向后请求网络数据
  if (index === this.totalCount() - 1) {
    // 实现向后加载数据的逻辑
    // this.pushItem(新数据);
  }
  
  return this._dataArray[index];
}

LazyForEach实现懒加载

LazyForEach是HarmonyOS提供的一种高效渲染大量数据的方式,它只会渲染当前可见的项目和少量缓存项,从而大大提高了性能。

Swiper(this.swiperController) {
  /**
   * 高性能知识点: 使用了cachedCount设置预加载的Text的数量,只在LazyForEach中生效,设置该属性后会缓存cachedCount个Text,LazyForEach超出显示和缓存范围的Text会被释放。
   */
  LazyForEach(this.data, (item: string, index: number) => {
    Text($r(item))
      .width($r('app.string.pageflip_full_size'))
      .height($r('app.string.pageflip_full_size'))
      .fontSize(this.textSize)
      .textAlign(TextAlign.Start)
      .align(Alignment.TopStart)
      .lineHeight($r('app.integer.flippage_text_lineheight'))
      .margin({
        top: $r('app.integer.flippage_margin_large'),
        left: $r('app.integer.flippage_padding_middle_two'),
        bottom: $r('app.integer.flippage_margin_middle')
      })
      .padding({
        left: $r('app.integer.flippage_padding_middle'),
        right: $r('app.integer.flippage_padding_middle'),
      })
      .id(`pageIndex${index}`)
  }, (item: string) => item)
}

LazyForEach接收三个参数:

  1. 数据源:提供数据的对象,必须实现IDataSource接口
  2. 项目生成器:一个回调函数,用于生成每个项目的UI
  3. 键生成器:一个回调函数,用于为每个项目生成唯一的键

cachedCount缓存策略

cachedCount是提高列表性能的关键参数,它指定了需要预加载和缓存的项目数量:

.cachedCount(CONFIGURATION.PAGEFLIPCACHECOUNT)

设置适当的缓存数量可以在用户翻页时提供更流畅的体验,因为下一页的内容已经预先加载和渲染好了。但缓存数量也不宜过大,否则会占用过多内存。

缓存策略的工作原理

  1. 当用户查看某一页时,系统会渲染当前页面
  2. 同时,系统会预加载和缓存cachedCount指定数量的前后页面
  3. 当用户翻到新页面时,新页面已经渲染好,可以立即显示
  4. 超出显示和缓存范围的页面会被释放,节省内存

Swiper组件配置

Swiper组件是实现左右翻页效果的核心,我们需要对其进行适当配置:

.index(this.currentPageNum - CONFIGURATION.PAGEFLIPPAGECOUNT)
.width($r('app.string.pageflip_full_size'))
.height($r('app.string.pageflip_full_size'))
.indicator(false)
.cachedCount(CONFIGURATION.PAGEFLIPCACHECOUNT)
.itemSpace(CONFIGURATION.PAGEFLIPZERO)
.loop(false)
.curve(Curve.Linear)
.effectMode(EdgeEffect.Fade)
.duration(CONFIGURATION.PAGEFLIPTOASTDURATION)
.onChange((index: number) => {
  this.currentPageNum = index + CONFIGURATION.PAGEFLIPPAGECOUNT; // 通过onChange监听当前处于第几页。
  this.selectedReadInfo = this.readInfoList[index];
})

关键配置说明:

  • index:设置当前显示的子组件索引
  • indicator:是否显示指示器
  • cachedCount:缓存数量
  • itemSpace:项目间距
  • loop:是否循环滑动
  • curve:动画曲线
  • effectMode:边缘效果模式
  • duration:动画持续时间
  • onChange:滑动切换回调

性能优化建议

基于上述实现,以下是一些性能优化建议:

  1. 合理设置cachedCount:根据应用场景和设备性能调整缓存数量,通常2-3个就足够了
  2. 延迟加载网络资源:在getData方法中实现网络请求,并且只在必要时(如接近数据源边界)才发起请求
  3. 避免重复渲染:确保键生成器返回唯一的键,避免不必要的重新渲染
  4. 简化UI结构:每个项目的UI结构应尽量简单,避免嵌套过深
  5. 使用资源引用:使用$r引用资源,而不是硬编码值

实际应用案例

在小说阅读器应用中,我们使用上述技术实现了高效的左右翻页功能。用户可以通过左右滑动或点击屏幕左右区域来翻页,体验流畅自然。

.onClick((event?: ClickEvent) => {
  if (!event) {
    return;
  }
  if (event.x > this.screenW / CONFIGURATION.PAGEFLIPTHREE * CONFIGURATION.PAGEFLIPTWO) {
    if (this.currentPageNum !== this.data.totalCount()) {
      this.swiperController.showNext();
    }
  } else if (event.x > this.screenW / CONFIGURATION.PAGEFLIPTHREE) {
    if (this.isMenuViewVisible) {
      this.isMenuViewVisible = false;
      this.isCommentVisible = false;
    } else {
      this.isMenuViewVisible = true;
      this.isCommentVisible = true;
    }
  } else {
    // 向左翻页
    if (this.currentPageNum !== CONFIGURATION.PAGEFLIPPAGESTART) {
      this.swiperController.showPrevious();
    }
  }
})

总结

通过本教程,我们详细讲解了HarmonyOS中高性能列表与懒加载技术的实现方法。通过合理使用SwiperLazyForEachcachedCount,我们可以实现高效流畅的列表体验,特别适合电子书阅读等需要大量内容展示的场景。

在实际应用中,我们还可以根据具体需求进行进一步优化,如使用虚拟列表、预加载图片等,以提升用户体验。

关键要点

  1. 使用BasicDataSource管理数据源,支持动态加载
  2. 使用LazyForEach实现懒加载,只渲染可见项目
  3. 通过cachedCount设置缓存策略,提高翻页流畅度
  4. 合理配置Swiper组件,实现自然的翻页效果
收藏00

登录 后评论。没有帐号? 注册 一个。