卡段优化

This commit is contained in:
Developer
2026-05-22 02:04:46 +08:00
parent 6d37d9aa69
commit e1d8c4521d
15 changed files with 1508 additions and 119 deletions

View File

@@ -0,0 +1,936 @@
# 移动端性能优化 — 智能节流方案 实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 在不阉割任何视觉效果和动画的前提下,通过智能节流策略消除移动端发热和高资源占用问题
**Architecture:** 创建 PerformanceOrchestrator 性能调度中心单例,统一管理帧率节流、动画可见性感知、后台服务休眠、特效互斥调度。各组件主动注册到调度器,由调度器根据性能级别、电量、前后台状态决定运行策略。
**Tech Stack:** Flutter/Dart, Riverpod, battery_plus, sensors_plus, visibility_detector
---
## 文件结构
### 新建文件
| 文件 | 职责 |
|------|------|
| `lib/core/services/performance/performance_orchestrator.dart` | 性能调度中心单例 — 帧率/级别/电量/前后台统一管理 |
| `lib/core/services/performance/app_lifecycle_gate.dart` | 前后台统一管理门 — 暂停/恢复后台服务和动画 |
| `lib/core/services/performance/effect_mutex.dart` | 特效互斥调度器 — 同一时刻限制重量级特效数量 |
### 修改文件
| 文件 | 修改内容 |
|------|---------|
| `lib/shared/widgets/shader_card_background.dart` | Shader 帧率节流 + 可见性暂停 |
| `lib/shared/widgets/appbar_character_sprite.dart` | 不可见时暂停 idle 动画 + setState→ValueNotifier |
| `lib/shared/widgets/tab_icon_sprite.dart` | 未选中 Tab 停止 glow 动画 |
| `lib/shared/widgets/glass_container.dart` | RepaintBoundary 包裹 + 缓存策略 |
| `lib/shared/widgets/glass_bottom_nav_bar.dart` | RepaintBoundary 包裹 |
| `lib/core/layout/app_shell.dart` | 集成 AppLifecycleGate |
| `lib/app/app.dart` | 集成 AppLifecycleGate + PerformanceOrchestrator 初始化 |
| `lib/main.dart` | 初始化 PerformanceOrchestrator |
| `lib/core/services/device/shake_detector.dart` | 前后台暂停/恢复 |
| `lib/core/services/clipboard_monitor_service.dart` | 前后台暂停/恢复 |
| `lib/core/services/device/battery_info_service.dart` | 前后台暂停/恢复轮询 |
| `lib/core/services/device/battery_optimization_service.dart` | 联动 PerformanceOrchestrator |
| `lib/core/utils/interaction_animations.dart` | CelebrationOverlay 按需激活 |
| `lib/features/home/presentation/home_refresh_indicator.dart` | setState→局部刷新 |
| `CHANGELOG.md` | 记录本次优化 |
---
## Task 1: 创建 PerformanceOrchestrator 性能调度中心
**Files:**
- Create: `lib/core/services/performance/performance_orchestrator.dart`
- [ ] **Step 1: 创建 PerformanceOrchestrator 单例**
```dart
// ============================================================
// 闲言APP — 性能调度中心
// 创建时间: 2026-05-22
// 更新时间: 2026-05-22
// 作用: 统一管理帧率节流/性能级别/电量联动/前后台切换
// 上次更新: 初始创建
// ============================================================
import 'dart:async';
import 'package:flutter/scheduler.dart';
import 'package:xianyan/core/services/device/battery_info_service.dart';
import 'package:xianyan/core/storage/app_kv_store.dart';
import 'package:xianyan/core/utils/logger.dart';
/// 性能级别
enum PerformanceLevel {
full('完整', 1, 1),
balanced('平衡', 2, 30),
saver('省电', 3, 20);
const PerformanceLevel(this.label, this.sortOrder, this.targetFps);
final String label;
final int sortOrder;
final int targetFps;
}
/// 帧率节流回调类型 — 返回 true 表示本帧需要更新
typedef FrameThrottleCallback = bool Function();
class PerformanceOrchestrator {
PerformanceOrchestrator._();
static final PerformanceOrchestrator instance = PerformanceOrchestrator._();
static const _keyLevel = 'performance_level';
PerformanceLevel _level = PerformanceLevel.full;
bool _isAppForeground = true;
StreamSubscription<BatteryInfo>? _batterySub;
final List<VoidCallback> _onForegroundCallbacks = [];
final List<VoidCallback> _onBackgroundCallbacks = [];
PerformanceLevel get level => _level;
bool get isAppForeground => _isAppForeground;
bool get shouldThrottleShader => _level != PerformanceLevel.full;
bool get shouldPauseAnimations => !_isAppForeground || _level == PerformanceLevel.saver;
/// 初始化 — 在 main() 中调用
Future<void> init() async {
final stored = AppKVStore.getString(_keyLevel);
_level = _resolveLevel(stored);
Log.i('PerformanceOrchestrator 初始化: level=${_level.label}');
_batterySub = BatteryInfoService.instance.onBatteryChanged.listen((info) {
if (info.isCritical && _level != PerformanceLevel.saver) {
setLevel(PerformanceLevel.saver);
Log.i('PerformanceOrchestrator: 电量严重不足,自动切换省电模式');
}
});
}
/// 设置性能级别
void setLevel(PerformanceLevel newLevel) {
if (_level == newLevel) return;
_level = newLevel;
AppKVStore.setString(_keyLevel, newLevel.name);
Log.i('PerformanceOrchestrator: 级别切换为 ${newLevel.label}');
}
/// App 进入前台
void onAppResumed() {
if (_isAppForeground) return;
_isAppForeground = true;
Log.i('PerformanceOrchestrator: App 回到前台');
for (final cb in _onForegroundCallbacks) {
cb();
}
}
/// App 进入后台
void onAppPaused() {
if (!_isAppForeground) return;
_isAppForeground = false;
Log.i('PerformanceOrchestrator: App 进入后台');
for (final cb in _onBackgroundCallbacks) {
cb();
}
}
/// 注册前台回调
void onForeground(VoidCallback callback) {
_onForegroundCallbacks.add(callback);
}
/// 注册后台回调
void onBackground(VoidCallback callback) {
_onBackgroundCallbacks.add(callback);
}
/// 移除回调
void removeCallbacks(VoidCallback callback) {
_onForegroundCallbacks.remove(callback);
_onBackgroundCallbacks.remove(callback);
}
/// 创建节流帧计数器 — 返回每 N 帧触发一次的判断函数
/// full: 每1帧, balanced: 每2帧, saver: 每3帧
FrameThrottleCallback createFrameThrottle() {
int frameCount = 0;
return () {
frameCount++;
final skip = switch (_level) {
PerformanceLevel.full => 1,
PerformanceLevel.balanced => 2,
PerformanceLevel.saver => 3,
};
if (frameCount % skip == 0) {
return true;
}
return false;
};
}
PerformanceLevel _resolveLevel(String? stored) {
return switch (stored) {
'full' => PerformanceLevel.full,
'balanced' => PerformanceLevel.balanced,
'saver' => PerformanceLevel.saver,
_ => PerformanceLevel.full,
};
}
void dispose() {
_batterySub?.cancel();
_onForegroundCallbacks.clear();
_onBackgroundCallbacks.clear();
}
}
```
- [ ] **Step 2: 验证文件创建**
Run: `dart analyze lib/core/services/performance/performance_orchestrator.dart`
Expected: 无错误
---
## Task 2: 创建 AppLifecycleGate 前后台管理门
**Files:**
- Create: `lib/core/services/performance/app_lifecycle_gate.dart`
- [ ] **Step 1: 创建 AppLifecycleGate**
```dart
// ============================================================
// 闲言APP — 前后台统一管理门
// 创建时间: 2026-05-22
// 更新时间: 2026-05-22
// 作用: 统一管理前后台切换时暂停/恢复后台服务和动画
// 上次更新: 初始创建
// ============================================================
import 'package:flutter/widgets.dart';
import 'package:xianyan/core/services/performance/performance_orchestrator.dart';
import 'package:xianyan/core/services/device/shake_detector.dart';
import 'package:xianyan/core/services/clipboard_monitor_service.dart';
import 'package:xianyan/core/services/device/battery_info_service.dart';
import 'package:xianyan/core/utils/logger.dart';
/// App 生命周期统一管理门
///
/// 在 App 根组件中混入,统一管理前后台切换时:
/// - 暂停/恢复传感器(摇一摇)
/// - 暂停/恢复剪贴板监控
/// - 暂停/恢复电池轮询
/// - 通知 PerformanceOrchestrator 前后台状态
mixin AppLifecycleGate on WidgetsBindingObserver {
bool _lifecycleGateInitialized = false;
void initLifecycleGate() {
if (_lifecycleGateInitialized) return;
_lifecycleGateInitialized = true;
WidgetsBinding.instance.addObserver(this);
}
void disposeLifecycleGate() {
WidgetsBinding.instance.removeObserver(this);
_lifecycleGateInitialized = false;
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
switch (state) {
case AppLifecycleState.paused:
_onEnterBackground();
case AppLifecycleState.resumed:
_onEnterForeground();
default:
break;
}
}
void _onEnterBackground() {
Log.i('AppLifecycleGate: 进入后台 — 暂停服务和动画');
PerformanceOrchestrator.instance.onAppPaused();
ShakeDetector.instance.stop();
ClipboardMonitorService.instance.stopMonitor();
BatteryInfoService.instance.pausePolling();
}
void _onEnterForeground() {
Log.i('AppLifecycleGate: 回到前台 — 恢复服务和动画');
PerformanceOrchestrator.instance.onAppResumed();
if (ShakeDetector.instance.isEnabled) {
ShakeDetector.instance.start();
}
if (ClipboardMonitorService.instance.isEnabled) {
ClipboardMonitorService.instance.startMonitor();
}
BatteryInfoService.instance.resumePolling();
}
}
```
- [ ] **Step 2: 为 BatteryInfoService 添加 pausePolling/resumePolling 方法**
修改 `lib/core/services/device/battery_info_service.dart`,添加:
```dart
bool _pollingPaused = false;
void pausePolling() {
_pollingPaused = true;
_pollTimer?.cancel();
_pollTimer = null;
Log.i('BatteryInfoService: 轮询已暂停');
}
void resumePolling() {
if (!_pollingPaused) return;
_pollingPaused = false;
_pollTimer?.cancel();
_pollTimer = Timer.periodic(const Duration(minutes: 5), (_) async {
try {
_currentLevel = await _battery.batteryLevel;
_notify();
} catch (_) {}
});
Log.i('BatteryInfoService: 轮询已恢复');
}
```
- [ ] **Step 3: 验证**
Run: `dart analyze lib/core/services/performance/app_lifecycle_gate.dart lib/core/services/device/battery_info_service.dart`
Expected: 无错误
---
## Task 3: 创建 EffectMutex 特效互斥调度器
**Files:**
- Create: `lib/core/services/performance/effect_mutex.dart`
- [ ] **Step 1: 创建 EffectMutex**
```dart
// ============================================================
// 闲言APP — 特效互斥调度器
// 创建时间: 2026-05-22
// 更新时间: 2026-05-22
// 作用: 限制同一时刻运行的重量级特效数量防止GPU过载
// 上次更新: 初始创建
// ============================================================
import 'dart:async';
import 'package:xianyan/core/utils/logger.dart';
/// 特效优先级
enum EffectPriority {
interaction(0),
entrance(1),
decoration(2);
const EffectPriority(this.value);
final int value;
}
/// 特效令牌 — 持有者表示正在运行一个重量级特效
class EffectToken {
EffectToken._(this._mutex, this.name);
final EffectMutex _mutex;
final String name;
bool _released = false;
bool get isActive => !_released;
void release() {
if (_released) return;
_released = true;
_mutex._release(this);
}
}
/// 特效互斥调度器
///
/// 限制同一时刻运行的重量级特效数量。
/// 当已有 maxConcurrent 个特效运行时,低优先级特效会被延迟。
class EffectMutex {
EffectMutex({this.maxConcurrent = 2});
final int maxConcurrent;
final List<EffectToken> _active = [];
final List<_PendingEffect> _pending = [];
/// 申请一个特效槽位
///
/// 如果当前活跃特效数未达上限,立即返回 token
/// 否则等待直到有槽位释放。
Future<EffectToken> acquire(String name, {EffectPriority priority = EffectPriority.decoration}) async {
if (_active.length < maxConcurrent) {
final token = EffectToken._(this, name);
_active.add(token);
Log.i('EffectMutex: "$name" 获得槽位 (${_active.length}/$maxConcurrent)');
return token;
}
final completer = Completer<EffectToken>();
_pending.add(_PendingEffect(name, priority, completer));
Log.i('EffectMutex: "$name" 排队等待 (优先级=${priority.name}, 队列=${_pending.length})');
return completer.future;
}
void _release(EffectToken token) {
_active.remove(token);
Log.i('EffectMutex: "${token.name}" 释放槽位 (${_active.length}/$maxConcurrent)');
if (_pending.isNotEmpty) {
_pending.sort((a, b) => a.priority.value.compareTo(b.priority.value));
final next = _pending.removeAt(0);
final newToken = EffectToken._(this, next.name);
_active.add(newToken);
next.completer.complete(newToken);
Log.i('EffectMutex: "${next.name}" 获得槽位 (${_active.length}/$maxConcurrent)');
}
}
}
class _PendingEffect {
_PendingEffect(this.name, this.priority, this.completer);
final String name;
final EffectPriority priority;
final Completer<EffectToken> completer;
}
```
- [ ] **Step 2: 验证**
Run: `dart analyze lib/core/services/performance/effect_mutex.dart`
Expected: 无错误
---
## Task 4: Shader 帧率节流 — 修改 ShaderCardBackground
**Files:**
- Modify: `lib/shared/widgets/shader_card_background.dart`
- [ ] **Step 1: 添加帧率节流 + 可见性感知**
`_ShaderCardBackgroundState` 修改为:
```dart
class _ShaderCardBackgroundState extends State<ShaderCardBackground>
with SingleTickerProviderStateMixin, WidgetsBindingObserver {
late Ticker _ticker;
final ValueNotifier<double> _timeNotifier = ValueNotifier(0);
ui.FragmentProgram? _program;
bool _loaded = false;
bool _isVisible = true;
late FrameThrottleCallback _shouldRenderFrame;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_shouldRenderFrame = PerformanceOrchestrator.instance.createFrameThrottle();
_ticker = createTicker(_onTick);
_ticker.start();
_loadShader();
PerformanceOrchestrator.instance.onForeground(_resumeTicker);
PerformanceOrchestrator.instance.onBackground(_pauseTicker);
}
void _pauseTicker() {
if (_ticker.isActive) _ticker.stop();
}
void _resumeTicker() {
if (!_ticker.isActive && _isVisible) _ticker.start();
}
void _onTick(Duration elapsed) {
if (!_shouldRenderFrame()) return;
_timeNotifier.value = elapsed.inMicroseconds / 1000000.0;
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.paused) {
_pauseTicker();
} else if (state == AppLifecycleState.resumed && _isVisible) {
_resumeTicker();
}
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
PerformanceOrchestrator.instance.removeCallbacks(_resumeTicker);
PerformanceOrchestrator.instance.removeCallbacks(_pauseTicker);
_ticker.dispose();
_timeNotifier.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (!_loaded || _program == null) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
const Color(0xFF6699EE).withValues(alpha: 0.6),
const Color(0xFFB366CC).withValues(alpha: 0.6),
],
),
),
);
}
return RepaintBoundary(
child: CustomPaint(
painter: _ShaderPainter(
program: _program!,
timeNotifier: _timeNotifier,
touch: widget.touchOffset ?? Offset.zero,
),
),
);
}
}
```
同时添加 import:
```dart
import 'package:xianyan/core/services/performance/performance_orchestrator.dart';
```
- [ ] **Step 2: 验证**
Run: `dart analyze lib/shared/widgets/shader_card_background.dart`
Expected: 无错误
---
## Task 5: 动画可见性感知 — 修改 AppBarCharacterSprite
**Files:**
- Modify: `lib/shared/widgets/appbar_character_sprite.dart`
- [ ] **Step 1: 添加前后台感知 + 不可见时暂停 idle 动画**
`AppBarCharacterSpriteState` 中添加:
```dart
// 在类顶部添加
bool _isAppForeground = true;
// 在 initState 末尾添加
PerformanceOrchestrator.instance.onForeground(_onForeground);
PerformanceOrchestrator.instance.onBackground(_onBackground);
// 添加方法
void _onForeground() {
_isAppForeground = true;
if (widget.animationIntensity > 0.0 && !_idleController.isAnimating) {
_idleController.repeat(reverse: true);
}
}
void _onBackground() {
_isAppForeground = false;
_idleController.stop();
}
// 修改 _idleController.repeat 的位置 — 在 initState 中
// 原来: if (widget.animationIntensity > 0.0) _idleController.repeat(reverse: true);
// 改为: if (widget.animationIntensity > 0.0 && _isAppForeground) _idleController.repeat(reverse: true);
// 在 didUpdateWidget 中修改 idle 恢复逻辑
// 原来: } else if (!_idleController.isAnimating) {
// 改为: } else if (!_idleController.isAnimating && _isAppForeground) {
// 在 dispose 中添加
PerformanceOrchestrator.instance.removeCallbacks(_onForeground);
PerformanceOrchestrator.instance.removeCallbacks(_onBackground);
```
添加 import:
```dart
import 'package:xianyan/core/services/performance/performance_orchestrator.dart';
```
- [ ] **Step 2: 优化 onPointerMove 中的 setState**
`onPointerMove` 中的 `setState(() {})` 替换为局部刷新。由于 `_eyeOffset``AnimatedBuilder` 内部使用,且 `AnimatedBuilder` 已经在监听 6 个 Controller所以 `_eyeOffset` 的变化需要触发重绘。最佳方案是将 `_eyeOffset` 改为 `ValueNotifier<Offset>`
```dart
// 替换 Offset _eyeOffset = Offset.zero; 为:
final ValueNotifier<Offset> _eyeOffsetNotifier = ValueNotifier(Offset.zero);
// onPointerMove 中替换 setState(() {}); 为:
_eyeOffsetNotifier.value = Offset(
(delta.dx / distance) * factor,
(delta.dy / distance) * factor,
);
// lookAtTitle 中替换 _eyeOffset = ... 为:
_eyeOffsetNotifier.value = const Offset(3.0, 0.0);
// 和:
_eyeOffsetNotifier.value = Offset.zero;
// AnimatedBuilder 的 animation 改为:
animation: Listenable.merge([
_bounceController,
_earController,
_noseController,
_cheekController,
_expressionController,
_idleController,
_eyeOffsetNotifier,
]),
// builder 内部替换 _eyeOffset 为 _eyeOffsetNotifier.value
// dispose 中添加:
_eyeOffsetNotifier.dispose();
```
- [ ] **Step 3: 验证**
Run: `dart analyze lib/shared/widgets/appbar_character_sprite.dart`
Expected: 无错误
---
## Task 6: Tab 动画节流 — 修改 TabIconSprite
**Files:**
- Modify: `lib/shared/widgets/tab_icon_sprite.dart`
- [ ] **Step 1: 未选中 Tab 停止 glow 呼吸动画**
`_TabIconSpriteState``didUpdateWidget` 中,当 Tab 从选中变为未选中时,`_glowController.stop()` 已经存在。需要确保未选中的 Tab 不运行 glow repeat
```dart
// 在 didUpdateWidget 中,!widget.isSelected && oldWidget.isSelected 分支
// 已有 _glowController.stop(); 确认无误
// 在 initState 中,只有 isSelected 时才 repeat glow
// 已有 if (widget.isSelected) { _glowController.repeat(reverse: true); }
// 确认无误
```
- [ ] **Step 2: 添加前后台感知**
```dart
// 在 _TabIconSpriteState 中添加
bool _isAppForeground = true;
// initState 末尾添加
PerformanceOrchestrator.instance.onForeground(_onForeground);
PerformanceOrchestrator.instance.onBackground(_onBackground);
void _onForeground() {
_isAppForeground = true;
if (widget.isSelected) {
_glowController.repeat(reverse: true);
}
}
void _onBackground() {
_isAppForeground = false;
_glowController.stop();
}
// dispose 中添加
PerformanceOrchestrator.instance.removeCallbacks(_onForeground);
PerformanceOrchestrator.instance.removeCallbacks(_onBackground);
```
添加 import:
```dart
import 'package:xianyan/core/services/performance/performance_orchestrator.dart';
```
- [ ] **Step 3: 验证**
Run: `dart analyze lib/shared/widgets/tab_icon_sprite.dart`
Expected: 无错误
---
## Task 7: BackdropFilter 缓存优化 — 修改 GlassContainer
**Files:**
- Modify: `lib/shared/widgets/glass_container.dart`
- [ ] **Step 1: 添加 RepaintBoundary 包裹**
`build` 方法中,将 `child``RepaintBoundary` 包裹,减少 BackdropFilter 的重绘范围:
```dart
// 在所有 _maybeBackdropFilter 调用中,将 child 参数用 RepaintBoundary 包裹
// 例如:
child: _maybeBackdropFilter(
sigma: cfg.blurSigma * multiplier,
child: RepaintBoundary(child: Padding(padding: effectivePadding, child: child)),
),
```
- [ ] **Step 2: 验证**
Run: `dart analyze lib/shared/widgets/glass_container.dart`
Expected: 无错误
---
## Task 8: GlassBottomNavBar 缓存优化
**Files:**
- Modify: `lib/shared/widgets/glass_bottom_nav_bar.dart`
- [ ] **Step 1: 添加 RepaintBoundary**
`build` 方法中,将整个 BackdropFilter 子树用 RepaintBoundary 包裹:
```dart
// 在 build 方法的 return Container(...) 外层包裹 RepaintBoundary
return RepaintBoundary(
child: Container(
margin: ...
...
),
);
```
- [ ] **Step 2: 验证**
Run: `dart analyze lib/shared/widgets/glass_bottom_nav_bar.dart`
Expected: 无错误
---
## Task 9: 集成 AppLifecycleGate 到 App 根组件
**Files:**
- Modify: `lib/app/app.dart`
- Modify: `lib/main.dart`
- [ ] **Step 1: 在 _XianyanAppState 中混入 AppLifecycleGate**
```dart
// 修改类声明
class _XianyanAppState extends ConsumerState<XianyanApp>
with WidgetsBindingObserver, AppLifecycleGate {
// 修改 initState
@override
void initState() {
super.initState();
initLifecycleGate();
}
// 修改 dispose
@override
void dispose() {
disposeLifecycleGate();
super.dispose();
}
// 删除原有的 didChangeAppLifecycleState 方法AppLifecycleGate 已处理)
// 但保留 AppLockService 相关逻辑,在 AppLifecycleGate 的重写中调用
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
switch (state) {
case AppLifecycleState.paused:
try { AppLockService.onAppPaused(); } catch (e) { Log.e('应用锁暂停处理失败', e); }
break;
case AppLifecycleState.resumed:
Future.microtask(() {
try { AppLockService.onAppResumed(); } catch (e) { Log.e('应用锁恢复处理失败', e); }
});
break;
default:
break;
}
}
```
添加 import:
```dart
import 'package:xianyan/core/services/performance/app_lifecycle_gate.dart';
```
- [ ] **Step 2: 在 main.dart 中初始化 PerformanceOrchestrator**
`main()` 函数中,`BatteryOptimizationService.init()` 之后添加:
```dart
try {
await PerformanceOrchestrator.instance.init();
if (pu.isOhos) Log.i('🟢 [OHOS] 性能调度中心初始化完成');
} catch (e, st) {
Log.e('性能调度中心初始化失败', e, st);
}
```
添加 import:
```dart
import 'core/services/performance/performance_orchestrator.dart';
```
- [ ] **Step 3: 验证**
Run: `dart analyze lib/app/app.dart lib/main.dart`
Expected: 无错误
---
## Task 10: CelebrationOverlay 按需激活
**Files:**
- Modify: `lib/core/utils/interaction_animations.dart`
- [ ] **Step 1: 修改 CelebrationOverlay 使用 EffectMutex**
```dart
// 在 CelebrationOverlayState 中添加
EffectToken? _effectToken;
// 修改 celebrate 方法
void celebrate() async {
final mutex = EffectMutex(maxConcurrent: 2);
_effectToken = await mutex.acquire('celebration', priority: EffectPriority.decoration);
_centerController.play();
}
// 在 ConfettiWidget 的 onComplete 或 _centerController 的状态监听中释放 token
// 修改 initState:
@override
void initState() {
super.initState();
_centerController = ConfettiController(
duration: const Duration(milliseconds: 1500),
);
_centerController.addListener(() {
if (_centerController.state == ConfettiControllerState.stopped && _effectToken != null) {
_effectToken!.release();
_effectToken = null;
}
});
}
```
添加 import:
```dart
import 'package:xianyan/core/services/performance/effect_mutex.dart';
```
- [ ] **Step 2: 验证**
Run: `dart analyze lib/core/utils/interaction_animations.dart`
Expected: 无错误
---
## Task 11: HomeRefreshIndicator 局部刷新优化
**Files:**
- Modify: `lib/features/home/presentation/home_refresh_indicator.dart`
- [ ] **Step 1: 将 _pullProgress 改为 ValueNotifier**
```dart
// 替换 double _pullProgress = 0.0; 为:
final ValueNotifier<double> _pullProgressNotifier = ValueNotifier(0.0);
// 替换所有 setState(() => _pullProgress = newProgress); 为:
_pullProgressNotifier.value = newProgress;
// 替换所有 _pullProgress 读取为 _pullProgressNotifier.value
// 在 _displayProgress getter 中使用 _pullProgressNotifier.value
// 在 _onResetTick 中,将 setState(() {}); 改为直接通知 _pullProgressNotifier
// 由于 _resetController 的 listener 已经在更新,只需确保 AnimatedBuilder 监听 _pullProgressNotifier
// 在 build 方法中,用 AnimatedBuilder 包裹需要响应 _pullProgress 的部分:
// 将 progress 变量改为从 _pullProgressNotifier 获取
```
注意:由于此文件较复杂,涉及多个状态变量(`_isRefreshing`, `_isComplete`, `_pullProgress`),最安全的做法是将 `_pullProgress` 改为 `ValueNotifier`,其他保持 `setState` 不变(因为它们变化频率低)。
- [ ] **Step 2: 验证**
Run: `dart analyze lib/features/home/presentation/home_refresh_indicator.dart`
Expected: 无错误
---
## Task 12: 全局编译验证 + CHANGELOG 更新
**Files:**
- Modify: `CHANGELOG.md`
- [ ] **Step 1: 运行全局编译验证**
Run: `cd e:\project\flutter\f\xianyan && flutter analyze`
Expected: 无错误
- [ ] **Step 2: 更新 CHANGELOG.md**
在文件顶部添加新版本记录:
```markdown
## [v14.82.0] - 2026-05-22
### 移动端性能优化 — 智能节流方案
**问题**移动端发热严重GPU/CPU 资源占用高,后台持续消耗电量
**根因分析**
- Fragment Shader 每帧 60fps 无间断运行
- 21+ 个 AnimationController 全天候运行(角色精灵 + Tab 图标)
- 149 处 BackdropFilter 每帧重新模糊
- 8+ 个后台服务持续监听(传感器/剪贴板/电池)
- 多个重量级特效同时运行Lottie + Confetti + Shader + Tilt
**优化方案**(不阉割任何视觉效果):
- ✅ 新增 PerformanceOrchestrator 性能调度中心 — 统一管理帧率/级别/电量联动
- ✅ Shader 帧率节流 — full 60fps / balanced 30fps / saver 20fps
- ✅ 动画前后台感知 — App 后台时自动暂停所有 repeat 动画
- ✅ BackdropFilter 缓存 — RepaintBoundary 减少重绘范围
- ✅ AppLifecycleGate 前后台管理门 — 统一暂停/恢复传感器和服务
- ✅ EffectMutex 特效互斥调度器 — 限制同时运行的重量级特效数量
- ✅ HomeRefreshIndicator 局部刷新 — ValueNotifier 替代 setState
- ✅ AppBarCharacterSprite 局部刷新 — _eyeOffset 改为 ValueNotifier
**新增文件**
- `lib/core/services/performance/performance_orchestrator.dart`
- `lib/core/services/performance/app_lifecycle_gate.dart`
- `lib/core/services/performance/effect_mutex.dart`
**预期效果**
- GPU 平均帧耗时 ↓60%
- 空闲 CPU 占用 ↓80%
- 后台 CPU 占用 ↓95%
- 电池续航接近正常 APP
```
- [ ] **Step 3: 最终验证**
Run: `cd e:\project\flutter\f\xianyan && flutter analyze`
Expected: 无错误