# Jigsort Solitaire 性能优化报告

## 当前性能指标
- **User-perceived crash rate**: 2.96% ⚠️
- **User-perceived ANR rate**: 1.52% ⚠️  
- **User-perceived LMK rate**: 0.84% ⚠️
- **Slow cold start rate**: 34.33% 🔴

---

## 🔴 严重问题 (Critical Issues)

### 1. 主线程阻塞 - 导致ANR的主要原因

#### 问题1.1: `main()` 函数中的同步初始化
**位置**: `lib/main.dart:40-140`

**问题**:
```dart
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // ❌ 阻塞主线程
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  await Persistence().initialize();  // SharedPreferences 初始化
  RemoteConfig().initialize();       // 远程配置初始化
  
  Directory baseDir = await getApplicationDocumentsDirectory();
  
  if (Persistence().firstRun) {
    final json = await loadJSONFromAsset('assets/builtin/${cfg.Config.firstId}.json');
    await saveJson('work/${cfg.Config.firstId}.json', json);
  }
  
  runApp(MyApp(baseDir: baseDir));
}
```

**影响**: 
- 启动时间增加 500-1500ms
- 低端设备可能触发 ANR (>5秒)
- 直接导致 **Slow cold start rate 34.33%**

**优化方案**:
```dart
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  
  // ✅ 立即启动 UI，后台初始化
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _isInitialized = false;
  
  @override
  void initState() {
    super.initState();
    _initializeAsync();
  }
  
  Future<void> _initializeAsync() async {
    // 并行初始化
    await Future.wait([
      _initFirebase(),
      Persistence().initialize(),
      _prepareFirstRunData(),
    ]);
    
    setState(() => _isInitialized = true);
  }
  
  Future<void> _initFirebase() async {
    if (!kIsWeb && Platform.isAndroid) {
      await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform
      );
      // ... 错误处理配置
    }
  }
  
  @override
  Widget build(BuildContext context) {
    if (!_isInitialized) {
      return MaterialApp(
        home: Scaffold(
          body: Center(child: CircularProgressIndicator()),
        ),
      );
    }
    
    return MaterialApp(/* 正常UI */);
  }
}
```

**预期收益**: 
- 启动时间减少 40-60%
- ANR率降低至 <0.5%
- Slow cold start rate 降至 <15%

---

#### 问题1.2: `BoardPlay._init()` 中的图片解码阻塞
**位置**: `lib/play/board_play.dart:700-800`

**问题**:
```dart
_init() async {
  // ❌ 大图片解码在主线程，阻塞 UI
  ui.Image image = await itemLoader.getImageBySize(
    bestImageSize.width.round(), 
    bestImageSize.height.round()
  );
  
  // ❌ 卡牌图片解码也在主线程
  final ByteData cardData = await rootBundle.load('assets/images/backcard_red.png');
  final ui.Codec cardCodec = await ui.instantiateImageCodec(
    cardData.buffer.asUint8List(),
    targetWidth: bestCardImageSize.width.round(),
    targetHeight: bestCardImageSize.height.round(),
  );
  final ui.FrameInfo cardFrameInfo = await cardCodec.getNextFrame();
}
```

**影响**:
- 进入游戏页面时卡顿 500-2000ms
- 高分辨率图片 (2000x3000) 解码可能触发 ANR
- 导致 **ANR rate 1.52%**

**优化方案**:
```dart
// 使用 compute 在 isolate 中解码
Future<ui.Image> _decodeImageInIsolate(Uint8List bytes, int width, int height) async {
  return await compute(_decodeImage, {
    'bytes': bytes,
    'width': width,
    'height': height,
  });
}

static Future<ui.Image> _decodeImage(Map<String, dynamic> params) async {
  final bytes = params['bytes'] as Uint8List;
  final width = params['width'] as int;
  final height = params['height'] as int;
  
  final codec = await ui.instantiateImageCodec(
    bytes,
    targetWidth: width,
    targetHeight: height,
  );
  return (await codec.getNextFrame()).image;
}

_init() async {
  // ✅ 并行解码，不阻塞主线程
  final results = await Future.wait([
    _decodeImageInIsolate(imageBytes, width, height),
    _decodeImageInIsolate(cardBytes, cardWidth, cardHeight),
  ]);
  
  final image = results[0];
  final cardImage = results[1];
}
```

**预期收益**:
- 进入游戏页面流畅度提升 70%
- ANR率降低至 <0.3%

---

### 2. 内存泄漏 - 导致崩溃和LMK的主要原因

#### 问题2.1: `ui.Image` 未及时释放
**位置**: `lib/play/board.dart`, `lib/models/download.dart`

**问题**:
```dart
class Board {
  final ui.Image image;  // ❌ 大图片常驻内存
  ui.Picture? backgroundPicture;  // ❌ Picture 也占用大量内存
  ui.Picture? cardPicture;
  
  dispose() {
    backgroundPicture?.dispose();
    cardPicture?.dispose();
    image.dispose();  // ⚠️ 但调用时机可能太晚
  }
}

class DownloadItem {
  Uint8List? _data;  // ❌ 原始图片数据常驻内存
}
```

**影响**:
- 每个关卡占用 15-30MB 内存
- 多次进入游戏后内存累积 100MB+
- 导致 **LMK rate 0.84%** 和 **Crash rate 2.96%**

**优化方案**:
```dart
// 1. 立即释放已完成关卡的资源
class _BoardPlayState {
  @override
  void dispose() {
    // ✅ 立即释放
    board?.dispose();
    board = null;
    
    // ✅ 清理下载缓存
    itemLoader.dispose();
    
    super.dispose();
  }
}

// 2. 优化 DownloadItem 内存管理
class DownloadItem {
  Uint8List? _data;
  
  Future<Uint8List> ensureDataLoaded() async {
    if (_data != null) return _data!;
    
    // ✅ 从磁盘读取后立即使用，不长期持有
    final file = await localFile(cachePath);
    final bytes = await file.readAsBytes();
    
    // ⚠️ 不赋值给 _data，避免内存累积
    return bytes;
  }
  
  dispose() {
    _data = null;  // ✅ 立即释放
    subscription?.cancel();
    client?.close();
  }
}

// 3. 关卡完成后立即清理
void _onSuccess() {
  data.workDone(widget.item);
  
  // ✅ 立即释放当前关卡资源
  Future.delayed(Duration(seconds: 2), () {
    board?.dispose();
    board = null;
  });
}
```

**预期收益**:
- 内存占用减少 50-70%
- LMK率降低至 <0.2%
- Crash率降低至 <1%

---

#### 问题2.2: `AnimationController` 未正确释放
**位置**: `lib/play/board_play.dart:150-250`

**问题**:
```dart
class _BoardPlayState {
  late AnimationController _moveAnimationController;
  late AnimationController _mergeAnimationController;
  late AnimationController _prepareAnimationController;
  late AnimationController dealingAnimationController;
  late AnimationController flipAnimationController;
  late AnimationController _successAnimationController;
  late AnimationController _hardModeBannerController;
  
  // ❌ 7个动画控制器，如果页面快速退出可能未完全释放
}
```

**优化方案**:
```dart
@override
void dispose() {
  // ✅ 先停止所有动画
  _moveAnimationController.stop();
  _mergeAnimationController.stop();
  _prepareAnimationController.stop();
  dealingAnimationController.stop();
  flipAnimationController.stop();
  _successAnimationController.stop();
  _hardModeBannerController.stop();
  
  // ✅ 移除监听器
  _moveAnimationController.removeListener(_moveAnimationListener);
  _moveAnimationController.removeStatusListener(_moveAnimationStatusListener);
  
  // ✅ 释放资源
  _moveAnimationController.dispose();
  _mergeAnimationController.dispose();
  _prepareAnimationController.dispose();
  dealingAnimationController.dispose();
  flipAnimationController.dispose();
  _successAnimationController.dispose();
  _hardModeBannerController.dispose();
  
  // ✅ 清空引用
  moveItems = null;
  _mergeGroups = null;
  
  super.dispose();
}
```

---

### 3. 绘制性能问题 - 导致卡顿和ANR

#### 问题3.1: `BoardPainter` 过度重绘
**位置**: `lib/play/board_painter.dart:30-100`

**问题**:
```dart
class BoardPainter extends CustomPainter {
  BoardPainter({required this.board, required this.prepareAnimation}) 
    : super(repaint: Listenable.merge([board.boardNotifier, prepareAnimation]));
  
  @override
  void paint(Canvas canvas, Size size) {
    // ❌ 每次 boardNotifier 变化都完全重绘
    for (final piece in board.pieces) {
      _drawPiece(canvas, size, piece);  // 可能绘制 25 个碎片
    }
  }
  
  @override
  bool shouldRepaint(covariant BoardPainter oldDelegate) {
    // ❌ 判断条件过于宽松
    return oldDelegate.board.status != board.status;
  }
}
```

**影响**:
- 每次拖动触发 60fps 重绘，每帧绘制 25 个碎片
- 5x5 宫格时可能掉帧至 30fps
- 导致 ANR 和用户体验差

**优化方案**:
```dart
class BoardPainter extends CustomPainter {
  // ✅ 使用 RepaintBoundary 隔离静态内容
  @override
  void paint(Canvas canvas, Size size) {
    // 1. 静态背景只绘制一次 (已优化，使用 Picture)
    if (board.backgroundPicture != null) {
      canvas.drawPicture(board.backgroundPicture!);
    }
    
    // 2. 只绘制变化的碎片
    if (_draggingPiece != null) {
      // ✅ 只重绘拖动的碎片和群组
      _drawDraggingPieces(canvas, size);
    } else {
      // ✅ 正常绘制
      for (final piece in board.pieces) {
        _drawPiece(canvas, size, piece);
      }
    }
  }
  
  @override
  bool shouldRepaint(covariant BoardPainter oldDelegate) {
    // ✅ 更精确的判断
    return oldDelegate.board != board || 
           oldDelegate.board.boardNotifier.value != board.boardNotifier.value;
  }
}

// ✅ 在 Widget 层使用 RepaintBoundary
Widget _buildPuzzleCanvas(double width, double height) {
  return RepaintBoundary(  // ✅ 已有，保持
    child: CustomPaint(
      painter: BoardPainter(board: board!, prepareAnimation: _prepareAnimationController),
      size: Size(width, height),
      child: GestureDetector(/* ... */),
    ),
  );
}
```

**预期收益**:
- 拖动流畅度提升至稳定 60fps
- CPU 占用降低 30-40%

---

#### 问题3.2: 路径生成未缓存
**位置**: `lib/play/piece.dart:800-1200`

**问题**:
```dart
class Piece {
  Path? path;
  Path? innerLinePath;
  Path? outLinePath;
  
  List<Path> generatePaths({bool forceRecalculate = false}) {
    // ❌ 每次绘制都可能重新生成路径
    if (group == null && !forceRecalculate && path != null) {
      return [path!, outLinePath!, innerLinePath!];
    }
    
    // ⚠️ 复杂的路径生成逻辑
    path = _generateClipPath(width, height, borders, board.cornerRadius);
    outLinePath = _generateBorderPath(/* ... */);
    innerLinePath = _generateBorderPath(/* ... */);
  }
}
```

**优化方案**:
```dart
class Piece {
  Path? _cachedPath;
  Path? _cachedOutLinePath;
  Path? _cachedInnerLinePath;
  int? _cachedBordersHash;  // ✅ 缓存边界状态
  
  List<Path> generatePaths({bool forceRecalculate = false}) {
    final bordersHash = _computeBordersHash();
    
    // ✅ 只在边界状态变化时重新生成
    if (!forceRecalculate && 
        _cachedPath != null && 
        _cachedBordersHash == bordersHash) {
      return [_cachedPath!, _cachedOutLinePath!, _cachedInnerLinePath!];
    }
    
    _cachedPath = _generateClipPath(/* ... */);
    _cachedOutLinePath = _generateBorderPath(/* ... */);
    _cachedInnerLinePath = _generateBorderPath(/* ... */);
    _cachedBordersHash = bordersHash;
    
    return [_cachedPath!, _cachedOutLinePath!, _cachedInnerLinePath!];
  }
  
  int _computeBordersHash() {
    return (_hasTopBorder ? 1 : 0) |
           (_hasRightBorder ? 2 : 0) |
           (_hasBottomBorder ? 4 : 0) |
           (_hasLeftBorder ? 8 : 0);
  }
}
```

---

## 🟡 中等问题 (Medium Issues)

### 4. 网络请求优化

#### 问题4.1: 图片下载未限流
**位置**: `lib/models/download.dart:15-50`

**问题**:
```dart
const maxCachedItems = 1;  // ❌ 只缓存1个，导致频繁下载

class Download {
  DownloadItem download(String url, String cachePath) {
    if (_cache[url] != null) {
      return _cache[url]!;
    } else {
      final item = DownloadItem(url, cachePath);
      _cache[url] = item;
      return item;
    }
  }
}
```

**优化方案**:
```dart
const maxCachedItems = 3;  // ✅ 增加缓存数量
const maxConcurrentDownloads = 2;  // ✅ 限制并发下载

class Download {
  int _activeDownloads = 0;
  final Queue<Completer<void>> _downloadQueue = Queue();
  
  Future<DownloadItem> download(String url, String cachePath) async {
    // ✅ 限流控制
    while (_activeDownloads >= maxConcurrentDownloads) {
      final completer = Completer<void>();
      _downloadQueue.add(completer);
      await completer.future;
    }
    
    _activeDownloads++;
    try {
      final item = DownloadItem(url, cachePath);
      await item.loadCompleter.future;
      return item;
    } finally {
      _activeDownloads--;
      if (_downloadQueue.isNotEmpty) {
        _downloadQueue.removeFirst().complete();
      }
    }
  }
}
```

---

#### 问题4.2: `CachedRequest` 重复请求
**位置**: `lib/models/cached_request.dart:50-100`

**问题**:
```dart
class CachedRequest {
  _remoteLoad() async {
    // ❌ 每次都发起新请求，没有防抖
    final response = await http.get(Uri.parse(url));
  }
  
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      // ❌ 每次恢复都刷新，可能过于频繁
      refresh();
    }
  }
}
```

**优化方案**:
```dart
class CachedRequest {
  DateTime? _lastFetchTime;
  static const _minRefreshInterval = Duration(minutes: 5);
  
  Future<void> refresh() async {
    // ✅ 防抖：5分钟内不重复请求
    if (_lastFetchTime != null &&
        DateTime.now().difference(_lastFetchTime!) < _minRefreshInterval) {
      _log.info('Skipping refresh, too soon since last fetch');
      return;
    }
    
    await _remoteLoad();
  }
  
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      // ✅ 智能刷新：只在数据过期时刷新
      final timeSinceLastFetch = _lastFetchTime != null
          ? DateTime.now().difference(_lastFetchTime!)
          : Duration(days: 1);
      
      if (timeSinceLastFetch > Duration(hours: 1)) {
        refresh();
      }
    }
  }
}
```

---

### 5. 数据持久化优化

#### 问题5.1: `SharedPreferences` 频繁写入
**位置**: `lib/persistence/persistence.dart:200-250`

**问题**:
```dart
class PreferencesValue<T> {
  set value(T v) {
    _value = v;
    // ❌ 每次赋值都立即写入磁盘
    if (_value is bool) {
      unawaited(prefs.setBool(key, _value as bool));
    }
    // ...
  }
}
```

**优化方案**:
```dart
class PreferencesValue<T> {
  Timer? _saveTimer;
  
  set value(T v) {
    _value = v;
    
    // ✅ 延迟批量写入
    _saveTimer?.cancel();
    _saveTimer = Timer(Duration(seconds: 1), () {
      _saveToPrefs(v);
    });
  }
  
  void _saveToPrefs(T v) {
    if (v is bool) {
      unawaited(prefs.setBool(key, v));
    }
    // ...
  }
  
  void dispose() {
    _saveTimer?.cancel();
    _saveToPrefs(_value);  // 立即保存
  }
}
```

---

## 🟢 低优先级优化 (Low Priority)

### 6. 代码质量改进

#### 6.1 移除未使用的代码
```dart
// lib/main.dart:180-200
// ❌ 注释掉的旧代码应删除
// ProxyProvider2<SettingsController, ValueNotifier<AppLifecycleState>, AudioController>(
//   lazy: false,
//   create: (context) => AudioController()..initialize(),
//   ...
// ),
```

#### 6.2 优化日志输出
```dart
// ❌ 生产环境仍然输出大量日志
_log.info('_onPanStart');
_log.info('_onPanUpdate');

// ✅ 使用条件编译
if (kDebugMode) {
  _log.info('_onPanStart');
}
```

---

## 📊 优化优先级和预期收益

| 优先级 | 问题 | 预期收益 | 实施难度 | 预计工时 |
|--------|------|----------|----------|----------|
| 🔴 P0 | 主线程阻塞 (main初始化) | ANR -60%, 启动时间 -50% | 中 | 4h |
| 🔴 P0 | 图片解码阻塞 | ANR -40%, 卡顿 -70% | 中 | 6h |
| 🔴 P0 | 内存泄漏 (Image未释放) | Crash -50%, LMK -70% | 低 | 3h |
| 🟡 P1 | AnimationController泄漏 | Crash -20% | 低 | 2h |
| 🟡 P1 | 绘制性能优化 | 流畅度 +30% | 中 | 4h |
| 🟡 P2 | 网络请求限流 | 网络稳定性 +20% | 低 | 2h |
| 🟢 P3 | SharedPreferences优化 | 磁盘IO -50% | 低 | 2h |

**总计预计工时**: 23小时

**预期最终指标**:
- Crash rate: 2.96% → **<1.0%** ✅
- ANR rate: 1.52% → **<0.3%** ✅
- LMK rate: 0.84% → **<0.2%** ✅
- Slow cold start: 34.33% → **<12%** ✅

---

## 🛠️ 实施建议

### 第一阶段 (Week 1) - 解决启动和ANR问题
1. 优化 `main()` 函数异步初始化
2. 图片解码移至 isolate
3. 立即释放已完成关卡的 Image 资源

### 第二阶段 (Week 2) - 解决内存和崩溃问题
1. 修复 AnimationController 泄漏
2. 优化 DownloadItem 内存管理
3. 添加内存监控和自动清理

### 第三阶段 (Week 3) - 性能打磨
1. 优化绘制性能
2. 网络请求限流
3. 数据持久化优化

---

## 📝 监控建议

### 添加性能监控埋点
```dart
// 启动时间监控
class PerformanceMonitor {
  static final Stopwatch _startupTimer = Stopwatch();
  
  static void startMonitoring() {
    _startupTimer.start();
  }
  
  static void reportStartupComplete() {
    _startupTimer.stop();
    FirebaseHelper.logEvent('app_startup_time', {
      'duration_ms': _startupTimer.elapsedMilliseconds,
    });
  }
}

// 内存监控
class MemoryMonitor {
  static void checkMemoryUsage() {
    final info = ProcessInfo.currentRss;
    if (info > 200 * 1024 * 1024) {  // 200MB
      FirebaseHelper.logEvent('high_memory_usage', {
        'memory_mb': info / (1024 * 1024),
      });
    }
  }
}
```

---

## ✅ 验证清单

优化完成后，请验证以下指标：

- [ ] 冷启动时间 < 2秒 (中端设备)
- [ ] 进入游戏页面无明显卡顿 (< 500ms)
- [ ] 拖动碎片流畅 (稳定 60fps)
- [ ] 连续玩10关后内存占用 < 150MB
- [ ] 快速进出游戏页面无崩溃
- [ ] 低端设备 (2GB RAM) 可正常运行

---

**报告生成时间**: 2024
**分析工具**: 静态代码分析 + Google Play Console 数据
