Flutter+HarmonyOS跨端实战—第14篇:性能优化与内存管理
·
打造流畅的 60fps 应用体验
前言
性能优化是移动应用开发的核心课题。一个性能良好的应用应该:
- 流畅运行:保持 60fps,无卡顿
- 快速响应:操作响应时间 < 100ms
- 内存稳定:无内存泄漏,内存占用合理
- 启动迅速:冷启动 < 3 秒
CleanMark AI 作为图片/视频处理应用,对性能要求更高。这篇文章我会带你系统性地优化应用性能。
一、性能分析工具
1.1 Flutter DevTools
启动 DevTools:
# 运行应用后,在终端执行
flutter pub global activate devtools
flutter pub global run devtools
核心功能:
| 工具 | 用途 |
|---|---|
| Performance | 分析帧率、重建次数、GPU 线程 |
| Memory | 监控内存使用、检测内存泄漏 |
| CPU Profiler | 分析 CPU 占用、热点函数 |
| Network | 监控网络请求 |
| Logging | 查看应用日志 |
1.2 性能指标
// lib/core/utils/performance_monitor.dart
import 'package:flutter/scheduler.dart';
import 'package:logger/logger.dart';
/// 性能监控工具
class PerformanceMonitor {
static final Logger _logger = Logger();
static int _frameCount = 0;
static DateTime? _lastTime;
/// 开始监控帧率
static void startMonitoring() {
SchedulerBinding.instance.addTimingsCallback(_onFrameCallback);
}
/// 停止监控
static void stopMonitoring() {
SchedulerBinding.instance.removeTimingsCallback(_onFrameCallback);
}
static void _onFrameCallback(List<FrameTiming> timings) {
_frameCount += timings.length;
final now = DateTime.now();
if (_lastTime != null) {
final elapsed = now.difference(_lastTime!);
if (elapsed.inSeconds >= 1) {
final fps = _frameCount / elapsed.inSeconds;
_logger.d('FPS: ${fps.toStringAsFixed(1)}');
// 检测掉帧
if (fps < 55) {
_logger.w('检测到掉帧: $fps fps');
}
_frameCount = 0;
_lastTime = now;
}
} else {
_lastTime = now;
}
// 检测单帧耗时
for (final timing in timings) {
final buildDuration = timing.buildDuration;
final rasterDuration = timing.rasterDuration;
// 单帧超过 16.67ms(60fps)视为掉帧
if (buildDuration.inMilliseconds > 16 ||
rasterDuration.inMilliseconds > 16) {
_logger.w(
'单帧耗时过长 - Build: ${buildDuration.inMilliseconds}ms, '
'Raster: ${rasterDuration.inMilliseconds}ms',
);
}
}
}
}
1.3 内存监控
// lib/core/utils/memory_monitor.dart
import 'dart:developer' as developer;
import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';
/// 内存监控工具
class MemoryMonitor {
static final Logger _logger = Logger();
/// 记录当前内存快照
static void snapshot(String tag) {
if (kDebugMode) {
developer.Timeline.instantSync(
'Memory Snapshot',
arguments: {'tag': tag},
);
_logger.d('内存快照: $tag');
}
}
/// 强制 GC(仅用于测试)
static void forceGC() {
if (kDebugMode) {
developer.Timeline.instantSync('Force GC');
_logger.d('强制 GC');
}
}
/// 监控 Widget 生命周期
static void trackWidget(String widgetName, String event) {
if (kDebugMode) {
_logger.d('Widget 生命周期: $widgetName - $event');
}
}
}
本篇小结(第一部分)
这部分我们完成了:
- ✅ Flutter DevTools 介绍
- ✅ 性能监控工具(帧率监控)
- ✅ 内存监控工具(快照、GC)
下一部分我会继续讲解 Widget 性能优化。
二、Widget 性能优化
2.1 const 构造函数
原则:能用 const 就用 const
// ❌ 错误:每次 build 都创建新实例
Widget build(BuildContext context) {
return Text('Hello');
}
// ✅ 正确:使用 const,复用实例
Widget build(BuildContext context) {
return const Text('Hello');
}
const 优化效果:
- 减少对象创建
- 减少 GC 压力
- 提升 build 性能
2.2 RepaintBoundary
隔离重绘区域:
// lib/shared/widgets/optimized_image.dart
class OptimizedImage extends StatelessWidget {
final String imageUrl;
const OptimizedImage({required this.imageUrl, super.key});
Widget build(BuildContext context) {
// 使用 RepaintBoundary 隔离图片重绘
return RepaintBoundary(
child: CachedNetworkImage(
imageUrl: imageUrl,
fit: BoxFit.cover,
),
);
}
}
使用场景:
- 复杂动画
- 频繁更新的区域
- 独立的图片/视频
2.3 Widget 拆分
原则:单个 build 方法不超过 40 行
// ❌ 错误:build 方法过长
class UserProfilePage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
// 100+ 行代码...
],
),
);
}
}
// ✅ 正确:拆分为独立 Widget
class UserProfilePage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
const _AvatarSection(),
const _InfoSection(),
const _ActionSection(),
],
),
);
}
}
class _AvatarSection extends StatelessWidget {
const _AvatarSection();
Widget build(BuildContext context) {
return Container(
// 头像区域
);
}
}
2.4 避免在 build 中创建对象
// ❌ 错误:每次 build 都创建新对象
Widget build(BuildContext context) {
final formatter = DateFormat('yyyy-MM-dd');
return Text(formatter.format(DateTime.now()));
}
// ✅ 正确:在 initState 或外部创建
class MyWidget extends StatefulWidget {
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late final DateFormat _formatter;
void initState() {
super.initState();
_formatter = DateFormat('yyyy-MM-dd');
}
Widget build(BuildContext context) {
return Text(_formatter.format(DateTime.now()));
}
}
2.5 Key 的正确使用
// ❌ 错误:使用索引作为 key
ListView.builder(
itemBuilder: (context, index) {
return ListTile(
key: ValueKey(index), // 数据变化时会出问题
title: Text(items[index].name),
);
},
);
// ✅ 正确:使用唯一标识作为 key
ListView.builder(
itemBuilder: (context, index) {
return ListTile(
key: ValueKey(items[index].id), // 使用数据的唯一 ID
title: Text(items[index].name),
);
},
);
2.6 避免不必要的 setState
// ❌ 错误:setState 范围过大
class CounterWidget extends StatefulWidget {
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _counter = 0;
Widget build(BuildContext context) {
return Column(
children: [
// 大量不需要更新的 Widget
const Header(),
const Banner(),
// 只有这里需要更新
Text('$_counter'),
ElevatedButton(
onPressed: () {
setState(() {
_counter++; // 整个 Column 都会重建
});
},
child: const Text('增加'),
),
],
);
}
}
// ✅ 正确:缩小 setState 范围
class CounterWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
const Header(),
const Banner(),
const _CounterDisplay(), // 只有这个 Widget 会重建
],
);
}
}
class _CounterDisplay extends StatefulWidget {
const _CounterDisplay();
State<_CounterDisplay> createState() => _CounterDisplayState();
}
class _CounterDisplayState extends State<_CounterDisplay> {
int _counter = 0;
Widget build(BuildContext context) {
return Column(
children: [
Text('$_counter'),
ElevatedButton(
onPressed: () {
setState(() {
_counter++; // 只重建 _CounterDisplay
});
},
child: const Text('增加'),
),
],
);
}
}
本篇小结(第二部分)
这部分我们完成了:
- ✅ const 构造函数优化
- ✅ RepaintBoundary 隔离重绘
- ✅ Widget 拆分策略
- ✅ 避免在 build 中创建对象
- ✅ Key 的正确使用
- ✅ 缩小 setState 范围
下一部分我会继续讲解列表和图片优化。
三、列表与图片优化
3.1 列表优化
使用 ListView.builder:
// ❌ 错误:一次性创建所有 Widget
ListView(
children: items.map((item) => ListTile(title: Text(item))).toList(),
)
// ✅ 正确:按需创建 Widget
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(title: Text(items[index]));
},
)
性能对比:
ListView(children: [...])- 一次性创建所有子 Widget,内存占用大ListView.builder- 只创建可见区域的 Widget,内存占用小
3.2 分页加载
// lib/shared/widgets/paginated_list.dart
class PaginatedList<T> extends StatefulWidget {
final Future<List<T>> Function(int page) onLoadMore;
final Widget Function(BuildContext, T) itemBuilder;
const PaginatedList({
required this.onLoadMore,
required this.itemBuilder,
super.key,
});
State<PaginatedList<T>> createState() => _PaginatedListState<T>();
}
class _PaginatedListState<T> extends State<PaginatedList<T>> {
final List<T> _items = [];
final ScrollController _scrollController = ScrollController();
int _currentPage = 1;
bool _isLoading = false;
bool _hasMore = true;
void initState() {
super.initState();
_loadMore();
_scrollController.addListener(_onScroll);
}
void dispose() {
_scrollController.dispose();
super.dispose();
}
void _onScroll() {
if (_scrollController.position.pixels >=
_scrollController.position.maxScrollExtent * 0.8) {
_loadMore();
}
}
Future<void> _loadMore() async {
if (_isLoading || !_hasMore) return;
setState(() {
_isLoading = true;
});
try {
final newItems = await widget.onLoadMore(_currentPage);
setState(() {
_items.addAll(newItems);
_currentPage++;
_hasMore = newItems.isNotEmpty;
_isLoading = false;
});
} catch (e) {
setState(() {
_isLoading = false;
});
}
}
Widget build(BuildContext context) {
return ListView.builder(
controller: _scrollController,
itemCount: _items.length + (_hasMore ? 1 : 0),
itemBuilder: (context, index) {
if (index == _items.length) {
return const Center(
child: Padding(
padding: EdgeInsets.all(16),
child: CircularProgressIndicator(),
),
);
}
return widget.itemBuilder(context, _items[index]);
},
);
}
}
3.3 图片优化
使用 CachedNetworkImage:
// ❌ 错误:直接使用 Image.network
Image.network(imageUrl)
// ✅ 正确:使用缓存
CachedNetworkImage(
imageUrl: imageUrl,
fit: BoxFit.cover,
placeholder: (context, url) => const CircularProgressIndicator(),
errorWidget: (context, url, error) => const Icon(Icons.error),
memCacheWidth: 800, // 限制内存缓存尺寸
maxWidthDiskCache: 1000, // 限制磁盘缓存尺寸
)
图片压缩:
// lib/core/utils/image_optimizer.dart
import 'dart:io';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:path_provider/path_provider.dart';
class ImageOptimizer {
/// 压缩图片
static Future<File?> compress(
File file, {
int quality = 85,
int maxWidth = 1920,
int maxHeight = 1920,
}) async {
try {
final tempDir = await getTemporaryDirectory();
final targetPath = '${tempDir.path}/${DateTime.now().millisecondsSinceEpoch}.jpg';
final result = await FlutterImageCompress.compressAndGetFile(
file.absolute.path,
targetPath,
quality: quality,
minWidth: maxWidth,
minHeight: maxHeight,
);
return result != null ? File(result.path) : null;
} catch (e) {
return null;
}
}
/// 获取图片尺寸
static Future<Size> getImageSize(File file) async {
final image = await decodeImageFromList(await file.readAsBytes());
return Size(image.width.toDouble(), image.height.toDouble());
}
}
3.4 缩略图生成
// lib/core/utils/thumbnail_generator.dart
import 'dart:io';
import 'package:video_thumbnail/video_thumbnail.dart';
import 'package:path_provider/path_provider.dart';
class ThumbnailGenerator {
/// 生成视频缩略图
static Future<File?> generateVideoThumbnail(String videoPath) async {
try {
final tempDir = await getTemporaryDirectory();
final thumbnailPath = await VideoThumbnail.thumbnailFile(
video: videoPath,
thumbnailPath: tempDir.path,
imageFormat: ImageFormat.JPEG,
maxWidth: 400,
quality: 75,
);
return thumbnailPath != null ? File(thumbnailPath) : null;
} catch (e) {
return null;
}
}
}
3.5 图片预加载
// lib/core/utils/image_preloader.dart
import 'package:flutter/material.dart';
class ImagePreloader {
/// 预加载图片列表
static Future<void> preloadImages(
BuildContext context,
List<String> imageUrls,
) async {
final futures = imageUrls.map((url) {
return precacheImage(NetworkImage(url), context);
});
await Future.wait(futures);
}
/// 预加载单张图片
static Future<void> preloadImage(
BuildContext context,
String imageUrl,
) async {
await precacheImage(NetworkImage(imageUrl), context);
}
}
3.6 内存缓存管理
// lib/core/utils/image_cache_manager.dart
import 'package:flutter/material.dart';
class ImageCacheManager {
/// 清除图片缓存
static void clearCache() {
imageCache.clear();
imageCache.clearLiveImages();
}
/// 设置缓存大小
static void configureCacheSize({
int maxCacheSize = 100, // 最多缓存 100 张图片
int maxCacheBytes = 50 << 20, // 最大 50MB
}) {
imageCache.maximumSize = maxCacheSize;
imageCache.maximumSizeBytes = maxCacheBytes;
}
/// 获取缓存状态
static Map<String, dynamic> getCacheStatus() {
return {
'currentSize': imageCache.currentSize,
'currentSizeBytes': imageCache.currentSizeBytes,
'liveImageCount': imageCache.liveImageCount,
'pendingImageCount': imageCache.pendingImageCount,
};
}
}
本篇小结(第三部分)
这部分我们完成了:
- ✅ 列表优化(ListView.builder + 分页加载)
- ✅ 图片缓存(CachedNetworkImage)
- ✅ 图片压缩(flutter_image_compress)
- ✅ 缩略图生成(video_thumbnail)
- ✅ 图片预加载(precacheImage)
- ✅ 内存缓存管理(imageCache 配置)
下一部分我会继续讲解内存管理和泄漏检测。
四、内存管理与泄漏检测
4.1 常见内存泄漏场景
1. 未释放的 Controller
// ❌ 错误:未释放 Controller
class MyPage extends StatefulWidget {
State<MyPage> createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
final TextEditingController _controller = TextEditingController();
Widget build(BuildContext context) {
return TextField(controller: _controller);
}
// 缺少 dispose
}
// ✅ 正确:及时释放
class _MyPageState extends State<MyPage> {
final TextEditingController _controller = TextEditingController();
void dispose() {
_controller.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return TextField(controller: _controller);
}
}
2. 未取消的 Stream 订阅
// ❌ 错误:未取消订阅
class _MyPageState extends State<MyPage> {
void initState() {
super.initState();
someStream.listen((data) {
// 处理数据
});
}
}
// ✅ 正确:取消订阅
class _MyPageState extends State<MyPage> {
StreamSubscription? _subscription;
void initState() {
super.initState();
_subscription = someStream.listen((data) {
// 处理数据
});
}
void dispose() {
_subscription?.cancel();
super.dispose();
}
}
3. 未取消的 Timer
// ❌ 错误:未取消 Timer
class _MyPageState extends State<MyPage> {
void initState() {
super.initState();
Timer.periodic(const Duration(seconds: 1), (timer) {
// 定时任务
});
}
}
// ✅ 正确:取消 Timer
class _MyPageState extends State<MyPage> {
Timer? _timer;
void initState() {
super.initState();
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
// 定时任务
});
}
void dispose() {
_timer?.cancel();
super.dispose();
}
}
4.2 资源管理工具类
// lib/core/utils/disposable_manager.dart
import 'dart:async';
import 'package:flutter/material.dart';
/// 资源管理器,统一管理需要释放的资源
class DisposableManager {
final List<VoidCallback> _disposables = [];
/// 添加需要释放的资源
void add(VoidCallback disposable) {
_disposables.add(disposable);
}
/// 添加 Controller
void addController(ChangeNotifier controller) {
_disposables.add(controller.dispose);
}
/// 添加 Stream 订阅
void addSubscription(StreamSubscription subscription) {
_disposables.add(subscription.cancel);
}
/// 添加 Timer
void addTimer(Timer timer) {
_disposables.add(timer.cancel);
}
/// 释放所有资源
void dispose() {
for (final disposable in _disposables) {
try {
disposable();
} catch (e) {
// 忽略释放错误
}
}
_disposables.clear();
}
}
/// 使用示例
class _MyPageState extends State<MyPage> {
final DisposableManager _disposables = DisposableManager();
void initState() {
super.initState();
// 添加 Controller
final controller = TextEditingController();
_disposables.addController(controller);
// 添加订阅
final subscription = someStream.listen((data) {});
_disposables.addSubscription(subscription);
// 添加 Timer
final timer = Timer.periodic(const Duration(seconds: 1), (timer) {});
_disposables.addTimer(timer);
}
void dispose() {
_disposables.dispose(); // 一次性释放所有资源
super.dispose();
}
}
4.3 内存泄漏检测
// lib/core/utils/leak_detector.dart
import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';
/// 内存泄漏检测器
class LeakDetector {
static final Logger _logger = Logger();
static final Map<String, int> _widgetCounts = {};
/// 记录 Widget 创建
static void onCreate(String widgetName) {
if (kDebugMode) {
_widgetCounts[widgetName] = (_widgetCounts[widgetName] ?? 0) + 1;
_logger.d('Widget 创建: $widgetName (总数: ${_widgetCounts[widgetName]})');
}
}
/// 记录 Widget 销毁
static void onDispose(String widgetName) {
if (kDebugMode) {
_widgetCounts[widgetName] = (_widgetCounts[widgetName] ?? 0) - 1;
_logger.d('Widget 销毁: $widgetName (总数: ${_widgetCounts[widgetName]})');
// 检测泄漏
if (_widgetCounts[widgetName]! < 0) {
_logger.e('检测到内存泄漏: $widgetName 销毁次数超过创建次数');
}
}
}
/// 打印统计信息
static void printStats() {
if (kDebugMode) {
_logger.i('Widget 实例统计:');
_widgetCounts.forEach((name, count) {
if (count > 0) {
_logger.w('$name: $count 个实例未释放');
}
});
}
}
}
/// 使用示例
class MyWidget extends StatefulWidget {
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
void initState() {
super.initState();
LeakDetector.onCreate('MyWidget');
}
void dispose() {
LeakDetector.onDispose('MyWidget');
super.dispose();
}
}
4.4 弱引用管理
// lib/core/utils/weak_reference_cache.dart
import 'dart:core';
/// 弱引用缓存,避免强引用导致的内存泄漏
class WeakReferenceCache<K, V> {
final Map<K, WeakReference<V>> _cache = {};
/// 添加缓存
void put(K key, V value) {
_cache[key] = WeakReference(value);
}
/// 获取缓存
V? get(K key) {
final ref = _cache[key];
final value = ref?.target;
// 如果对象已被 GC,清除缓存
if (value == null) {
_cache.remove(key);
}
return value;
}
/// 清除缓存
void clear() {
_cache.clear();
}
/// 清除已失效的缓存
void cleanUp() {
_cache.removeWhere((key, ref) => ref.target == null);
}
}
4.5 内存优化最佳实践
1. 及时释放大对象
class ImageProcessingPage extends StatefulWidget {
State<ImageProcessingPage> createState() => _ImageProcessingPageState();
}
class _ImageProcessingPageState extends State<ImageProcessingPage> {
Uint8List? _imageData;
Future<void> _processImage() async {
// 处理图片
_imageData = await loadImage();
// ... 处理逻辑
}
void dispose() {
// 释放大对象
_imageData = null;
super.dispose();
}
}
2. 使用 AutomaticKeepAliveClientMixin 保持状态
// 对于需要保持状态的 Tab 页面
class MyTabPage extends StatefulWidget {
State<MyTabPage> createState() => _MyTabPageState();
}
class _MyTabPageState extends State<MyTabPage>
with AutomaticKeepAliveClientMixin {
bool get wantKeepAlive => true;
Widget build(BuildContext context) {
super.build(context); // 必须调用
return Container();
}
}
3. 避免循环引用
// ❌ 错误:循环引用
class Parent {
Child? child;
}
class Child {
Parent parent; // 强引用父对象
Child(this.parent);
}
// ✅ 正确:使用弱引用
class Child {
WeakReference<Parent> parentRef;
Child(Parent parent) : parentRef = WeakReference(parent);
Parent? get parent => parentRef.target;
}
本篇小结(第四部分)
这部分我们完成了:
- ✅ 常见内存泄漏场景(Controller、Stream、Timer)
- ✅ 资源管理工具类(DisposableManager)
- ✅ 内存泄漏检测器(LeakDetector)
- ✅ 弱引用缓存(WeakReferenceCache)
- ✅ 内存优化最佳实践
下一部分我会总结本篇的关键要点。
五、完整小结
本篇完整小结
这篇文章我们完成了:
- ✅ 性能分析工具(Flutter DevTools + 帧率监控)
- ✅ Widget 性能优化(const、RepaintBoundary、拆分、Key)
- ✅ 列表优化(ListView.builder + 分页加载)
- ✅ 图片优化(缓存、压缩、预加载)
- ✅ 内存管理(资源释放、泄漏检测)
- ✅ 最佳实践(弱引用、循环引用避免)
关键要点:
性能优化金字塔
用户体验
↗ ↖
流畅度 60fps 快速响应
↗ ↖
Widget 优化 列表优化
↗ ↖
图片优化 内存管理
↘ ↙
性能监控
Widget 优化清单
| 优化项 | 方法 | 效果 |
|---|---|---|
| 减少重建 | const 构造函数 | 复用实例,减少 GC |
| 隔离重绘 | RepaintBoundary | 缩小重绘范围 |
| 拆分 Widget | 独立组件 | 精确控制更新范围 |
| 避免创建对象 | 提前初始化 | 减少 build 耗时 |
| 正确使用 Key | ValueKey(id) | 避免不必要的重建 |
| 缩小 setState | 拆分 StatefulWidget | 减少重建范围 |
列表优化策略
1. 选择正确的列表组件
// 数据量 < 20:ListView(children: [...])
// 数据量 > 20:ListView.builder
// 需要分组:ListView.separated
// 需要网格:GridView.builder
// 需要瀑布流:MasonryGridView
2. 分页加载
- 滚动到 80% 时触发加载
- 显示加载指示器
- 处理加载失败
3. 缓存高度
// 对于固定高度的列表项,使用 itemExtent
ListView.builder(
itemExtent: 80, // 固定高度,提升性能
itemBuilder: (context, index) => ...,
)
图片优化策略
1. 三级缓存
内存缓存(最快)
↓ 未命中
磁盘缓存(较快)
↓ 未命中
网络加载(最慢)
2. 尺寸控制
CachedNetworkImage(
imageUrl: url,
memCacheWidth: 800, // 内存缓存宽度
maxWidthDiskCache: 1000, // 磁盘缓存宽度
)
3. 压缩策略
- 上传前压缩:quality: 85, maxWidth: 1920
- 缩略图:quality: 75, maxWidth: 400
- 头像:quality: 80, maxWidth: 200
内存管理原则
1. 及时释放资源
void dispose() {
// 释放顺序:先释放子资源,再释放父资源
_controller.dispose();
_subscription?.cancel();
_timer?.cancel();
super.dispose();
}
2. 避免内存泄漏
- Controller 未释放
- Stream 订阅未取消
- Timer 未取消
- 循环引用
- 静态变量持有 Widget 引用
3. 大对象管理
// 使用完立即释放
Uint8List? imageData = await loadImage();
// ... 使用 imageData
imageData = null; // 释放引用
性能监控指标
| 指标 | 目标值 | 说明 |
|---|---|---|
| 帧率 | ≥ 55 fps | 低于 55 fps 用户可感知卡顿 |
| 单帧耗时 | ≤ 16ms | 超过 16ms 会掉帧 |
| 内存占用 | < 200MB | 根据设备性能调整 |
| 启动时间 | < 3s | 冷启动时间 |
| 页面切换 | < 300ms | 页面切换动画时间 |
性能优化流程
1. 性能分析
↓ 使用 DevTools 定位问题
2. 确定瓶颈
↓ 帧率、内存、CPU
3. 针对性优化
↓ Widget、列表、图片
4. 验证效果
↓ 对比优化前后数据
5. 持续监控
↓ 生产环境监控
HarmonyOS 适配要点
1. 内存限制更严格
- HarmonyOS 对应用内存限制更严格
- 及时释放大对象
- 使用弱引用缓存
2. 图片加载优化
// HarmonyOS 推荐使用较小的缓存尺寸
if (PlatformUtils.isHarmonyOS) {
imageCache.maximumSize = 50; // 减少缓存数量
imageCache.maximumSizeBytes = 30 << 20; // 30MB
}
3. 列表性能
- HarmonyOS 设备性能差异大
- 使用 itemExtent 提升性能
- 避免复杂的列表项布局
调试技巧
1. 性能叠加层
// main.dart
void main() {
runApp(
MaterialApp(
showPerformanceOverlay: true, // 显示性能叠加层
home: MyApp(),
),
);
}
2. 检查重建次数
Widget build(BuildContext context) {
print('${widget.runtimeType} build'); // 打印重建日志
return Container();
}
3. 内存快照对比
// 操作前
MemoryMonitor.snapshot('before_operation');
// 执行操作
await heavyOperation();
// 操作后
MemoryMonitor.snapshot('after_operation');
// 在 DevTools 中对比两个快照
思考题
- 为什么 const 构造函数能提升性能?(提示:对象复用)
- RepaintBoundary 应该放在哪里?(提示:独立更新的区域)
- 如何检测应用中的内存泄漏?(提示:DevTools Memory 工具)
下一篇预告:第15篇 - 测试与部署
更多推荐

所有评论(0)