Flutter for OpenHarmony二手物品置换App实战 - 列表性能优化实现

列表是App中最常见的UI组件,商品列表、消息列表、搜索结果等都是列表。当列表数据量大时,性能优化就变得很重要。今天我们来讲解列表性能优化的实现方式。

列表性能问题的来源

列表性能问题主要来自两个方面:一是创建了太多Widget,二是图片加载消耗资源。优化的核心思路是懒加载和缓存。Flutter的渲染机制决定了Widget数量直接影响内存占用和渲染速度,所以控制Widget数量是优化的关键。

使用ListView.builder

dart 复制代码
// 不推荐:一次性创建所有Widget
ListView(
  children: products.map((p) => ProductCard(product: p)).toList(),
)

// 推荐:懒加载,只创建可见区域的Widget
ListView.builder(
  itemCount: products.length,
  itemBuilder: (context, index) => ProductCard(product: products[index]),
)

普通ListView会一次性创建所有子Widget,如果有1000条数据就创建1000个Widget,内存直接爆炸。ListView.builder采用懒加载策略,只创建屏幕可见区域的Widget,滚动时动态创建新的、销毁离开屏幕的。这是列表优化最基本也是最重要的一步。

使用GridView.builder

商品列表用网格布局:

dart 复制代码
GridView.builder(
  padding: const EdgeInsets.all(12),
  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,
    childAspectRatio: 0.65,
    crossAxisSpacing: 10,
    mainAxisSpacing: 10,
  ),
  itemCount: _products.length,
  itemBuilder: (context, index) => _buildProductCard(_products[index]),
)

GridView.builder和ListView.builder原理一样,都是懒加载。gridDelegate定义网格的布局规则,crossAxisCount设置每行显示2个,childAspectRatio是宽高比,spacing是间距。这些参数都用const修饰,避免每次build都创建新对象。

使用SliverGrid

CustomScrollView中使用SliverGrid

dart 复制代码
CustomScrollView(
  slivers: [
    SliverToBoxAdapter(child: _buildBanner()),
    SliverToBoxAdapter(child: _buildCategories()),
    SliverPadding(
      padding: const EdgeInsets.all(12),
      sliver: SliverGrid(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
          childAspectRatio: 0.65,
          crossAxisSpacing: 10,
          mainAxisSpacing: 10,
        ),
        delegate: SliverChildBuilderDelegate(
          (context, index) => _buildProductCard(_products[index]),
          childCount: _products.length,
        ),
      ),
    ),
  ],
)

首页通常有banner、分类导航、商品列表等多个部分,用CustomScrollView可以把它们组合成一个可滚动的整体。SliverChildBuilderDelegate实现懒加载,效果和GridView.builder一样。这种写法更灵活,可以在列表前后插入任意内容。

图片缓存

使用cached_network_image缓存网络图片:

dart 复制代码
CachedNetworkImage(
  imageUrl: product['image'],
  fit: BoxFit.cover,
  placeholder: (context, url) => Container(
    color: Colors.grey[200],
    child: const Center(child: CircularProgressIndicator()),
  ),
  errorWidget: (context, url, error) => Container(
    color: Colors.grey[200],
    child: Icon(Icons.image, size: 60, color: Colors.grey[400]),
  ),
)

网络图片是列表性能的大敌,每次滚动都重新下载会很卡。CachedNetworkImage会把下载的图片缓存到本地,下次显示直接从缓存读取。placeholder在加载时显示占位内容,errorWidget在加载失败时显示错误提示,用户体验更好。

图片尺寸优化

加载适合显示尺寸的图片,不要加载原图:

dart 复制代码
// 假设服务器支持图片尺寸参数
String getImageUrl(String url, {int width = 200}) {
  return '$url?w=$width';
}

CachedNetworkImage(
  imageUrl: getImageUrl(product['image'], width: 200),
  // ...
)

商品卡片可能只有200像素宽,但原图可能是2000像素。加载原图不仅浪费流量,还会占用大量内存。让服务器返回合适尺寸的图片,或者使用CDN的图片处理功能,能大幅减少资源消耗。

使用const构造函数

能用const的地方都用const

dart 复制代码
// 不推荐
Container(
  padding: EdgeInsets.all(16),
  child: Text('文字'),
)

// 推荐
Container(
  padding: const EdgeInsets.all(16),
  child: const Text('文字'),
)

const对象在编译期就创建好了,运行时直接复用,不需要每次build都重新创建。这个优化看起来微不足道,但在列表中累积起来效果很明显。养成习惯,能加const的地方都加上。

避免在build中创建对象

dart 复制代码
// 不推荐:每次build都创建新的列表
@override
Widget build(BuildContext context) {
  final categories = [
    {'icon': Icons.phone_android, 'name': '数码'},
    {'icon': Icons.checkroom, 'name': '服饰'},
    // ...
  ];
  return // ...
}

// 推荐:在State中定义,只创建一次
class _HomePageState extends State<HomePage> {
  final List<Map<String, dynamic>> _categories = [
    {'icon': Icons.phone_android, 'name': '数码'},
    {'icon': Icons.checkroom, 'name': '服饰'},
    // ...
  ];
  
  @override
  Widget build(BuildContext context) {
    return // ...
  }
}

build方法可能会被频繁调用,每次调用都创建新对象会产生大量垃圾回收压力。把不变的数据定义在State中,或者用final修饰,只创建一次就够了。

使用RepaintBoundary

对于复杂的Widget,用RepaintBoundary隔离重绘:

dart 复制代码
RepaintBoundary(
  child: _buildProductCard(product),
)

Flutter默认会把相邻的Widget合并到一个图层一起绘制,一个Widget变化可能导致整个区域重绘。RepaintBoundary创建独立的图层,内部变化不会影响外部,外部变化也不会导致内部重绘。对于复杂的商品卡片,这个优化很有效。

使用AutomaticKeepAliveClientMixin

PageViewTabBarView中保持页面状态:

dart 复制代码
class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;
  
  @override
  Widget build(BuildContext context) {
    super.build(context);  // 必须调用
    return // ...
  }
}

默认情况下,切换Tab时不可见的页面会被销毁,再切回来要重新加载。使用AutomaticKeepAliveClientMixin可以保持页面状态,滚动位置、加载的数据都会保留。注意build方法里必须调用super.build(context)。

分页加载

不要一次加载所有数据,分页加载:

dart 复制代码
class _HomePageState extends State<HomePage> {
  List<Map<String, dynamic>> _products = [];
  int _page = 1;
  bool _hasMore = true;
  bool _isLoadingMore = false;

  Future<void> _loadMoreProducts() async {
    if (_isLoadingMore || !_hasMore) return;
    
    setState(() => _isLoadingMore = true);
    
    try {
      _page++;
      final data = await Api.getProducts(page: _page);
      setState(() {
        _products.addAll(data);
        _hasMore = data.length >= 20;
        _isLoadingMore = false;
      });
    } catch (e) {
      _page--;
      setState(() => _isLoadingMore = false);
    }
  }
}

一次加载1000条数据,不管是网络传输还是内存占用都是灾难。分页加载每次只请求20条,滚动到底部时再加载下一页。_isLoadingMore防止重复请求,_hasMore判断是否还有更多数据,加载失败时回退页码。

使用itemExtent

如果列表项高度固定,指定itemExtent

dart 复制代码
ListView.builder(
  itemExtent: 100,  // 每项高度100
  itemCount: products.length,
  itemBuilder: (context, index) => ProductCard(product: products[index]),
)

指定itemExtent后,Flutter不需要调用每个子Widget的layout来计算高度,可以直接通过数学计算确定哪些项在可见区域。这对于长列表的滚动性能提升很明显。

小结

这篇讲解了列表性能优化的实现方式,包括使用builder懒加载、图片缓存、const构造函数、RepaintBoundary、分页加载等。性能优化能让App更流畅,提升用户体验。记住优化的核心思路:减少Widget数量、减少重绘、减少内存占用。


欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

相关推荐
Miguo94well2 小时前
Flutter框架跨平台鸿蒙开发——歌词制作器APP的开发流程
flutter·华为·harmonyos·鸿蒙
晚霞的不甘2 小时前
Flutter for OpenHarmony 进阶实战:打造 60FPS 流畅的物理切水果游戏
javascript·flutter·游戏·云原生·正则表达式
雨季6662 小时前
构建 OpenHarmony 文本高亮关键词标记器:用纯字符串操作实现智能标注
开发语言·javascript·flutter·ui·ecmascript·dart
b2077212 小时前
Flutter for OpenHarmony 身体健康状况记录App实战 - 体重趋势实现
python·flutter·harmonyos
b2077212 小时前
Flutter for OpenHarmony 身体健康状况记录App实战 - 个人中心实现
android·java·python·flutter·harmonyos
灰灰勇闯IT2 小时前
Flutter for OpenHarmony:布局组件实战指南
前端·javascript·flutter
Miguo94well3 小时前
Flutter框架跨平台鸿蒙开发——科目一题目练习APP的开发流程
flutter·华为·harmonyos
国科安芯3 小时前
永磁同步电机驱动控制系统中MCU的抗干扰设计
单片机·嵌入式硬件·性能优化·架构·安全性测试
●VON3 小时前
Flutter 与 OpenHarmony 应用功能深化:构建独立任务表单页面与完善编辑体验
学习·flutter·openharmony·von