flutter-debugging

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Logging

日志记录

  • Use a centralized
    AppLogger
    class for all logging — NEVER use
    print()
    or raw
    debugPrint()
  • Define log levels:
    verbose
    ,
    debug
    ,
    info
    ,
    warning
    ,
    error
    ,
    fatal
  • In dev flavor: log everything (verbose and above)
  • In staging: log info and above
  • In production: log warning and above only, route to Crashlytics
  • Include context in logs:
    AppLogger.error('Failed to fetch user', error: e, stackTrace: st)
  • NEVER log sensitive data (passwords, tokens, PII) at any level
  • 使用统一的
    AppLogger
    类处理所有日志,绝对不要使用
    print()
    或原生
    debugPrint()
  • 定义日志等级:
    verbose
    debug
    info
    warning
    error
    fatal
  • 开发环境:记录所有等级日志(verbose及以上)
  • 预发布环境:记录info及以上等级日志
  • 生产环境:仅记录warning及以上等级日志,并上报至Crashlytics
  • 日志中需包含上下文信息:例如
    AppLogger.error('Failed to fetch user', error: e, stackTrace: st)
  • 任何日志等级下都绝对不要记录敏感数据(密码、令牌、PII个人可识别信息)

Flutter DevTools

Flutter DevTools

  • Use Widget Inspector to debug layout issues and identify unnecessary rebuilds
  • Use Performance Overlay (
    showPerformanceOverlay: true
    ) to monitor frame rates
  • Use Timeline View to identify jank — target 16ms per frame (60fps)
  • Use Memory View to detect memory leaks and monitor allocation patterns
  • Use Network Profiler to inspect Dio requests/responses during development
  • 使用 Widget Inspector 调试布局问题,识别不必要的组件重绘
  • 使用 Performance Overlay
    showPerformanceOverlay: true
    )监测帧率
  • 使用 Timeline View 识别卡顿,目标为每帧16ms(60fps)
  • 使用 Memory View 检测内存泄漏,监测内存分配模式
  • 使用 Network Profiler 在开发阶段检查Dio请求/响应

Debugging Strategies

调试策略

  • Layout Issues: Use
    debugPaintSizeEnabled = true
    to visualize widget boundaries
  • Overflow Errors: Check
    RenderFlex overflowed
    — use
    Expanded
    ,
    Flexible
    , or constrain dimensions
  • Unbounded Height: Wrap
    ListView
    in
    SizedBox
    or use
    shrinkWrap: true
    with
    NeverScrollableScrollPhysics
  • Rebuild Tracking: Add
    debugPrint('$runtimeType rebuild')
    temporarily to identify excessive rebuilds — remove before commit
  • Async Errors: Always catch and log errors in
    try-catch
    blocks with stack traces
  • Use
    assert()
    for development-time invariant checks that are stripped in release builds
  • 布局问题:设置
    debugPaintSizeEnabled = true
    可视化组件边界
  • 溢出错误:排查
    RenderFlex overflowed
    问题,使用
    Expanded
    Flexible
    或限制尺寸解决
  • 高度无界问题:将
    ListView
    包裹在
    SizedBox
    中,或搭配
    shrinkWrap: true
    NeverScrollableScrollPhysics
    使用
  • 重绘追踪:临时添加
    debugPrint('$runtimeType rebuild')
    识别过度重绘,代码提交前务必删除
  • 异步错误:始终在
    try-catch
    块中捕获并记录错误及堆栈信息
  • 使用
    assert()
    做开发阶段不变量检查,该语句会在Release构建中自动移除

Memory Management

内存管理

  • Dispose ALL controllers, subscriptions,
    Timer
    , and
    AnimationController
    in
    dispose()
  • Use
    late
    initialization in
    initState()
    — never inline-initialize disposable objects
  • Use
    WeakReference
    for caches that should not prevent garbage collection
  • Profile memory with DevTools Memory tab — watch for monotonically increasing allocations
  • Watch for common leaks: undisposed listeners, closures capturing
    BuildContext
    , global streams without cancellation
  • dispose()
    方法中释放所有控制器、订阅、
    Timer
    AnimationController
  • initState()
    中使用
    late
    初始化可释放对象,绝对不要内联初始化需要销毁的对象
  • 缓存场景使用
    WeakReference
    ,避免阻止垃圾回收
  • 使用DevTools的Memory标签页分析内存,关注持续增长的内存分配情况
  • 注意常见泄漏场景:未释放的监听器、捕获了
    BuildContext
    的闭包、未取消的全局流

Performance Profiling

性能分析

  • Always profile with
    --profile
    mode (not debug):
    flutter run --profile --flavor dev -t lib/main_dev.dart
  • Use
    Timeline.startSync
    /
    Timeline.finishSync
    for custom performance tracing of critical paths
  • Monitor shader compilation jank on first run — use
    --cache-sksl
    for warmup:
    bash
    flutter run --profile --cache-sksl --purge-persistent-cache
  • Target metrics: < 16ms frame build time, < 100ms screen transition, < 2s cold start
  • 始终使用
    --profile
    模式(而非debug模式)进行性能分析:
    flutter run --profile --flavor dev -t lib/main_dev.dart
  • 对关键路径使用
    Timeline.startSync
    /
    Timeline.finishSync
    做自定义性能打点
  • 监测首次运行时的着色器编译卡顿,使用
    --cache-sksl
    进行预热:
    bash
    flutter run --profile --cache-sksl --purge-persistent-cache
  • 目标指标:帧构建耗时<16ms,页面切换耗时<100ms,冷启动耗时<2s

Error Boundaries

错误边界

  • Route errors to Crashlytics in staging/prod (
    FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError
    )
  • Set
    FlutterError.onError
    and
    PlatformDispatcher.instance.onError
    to catch framework and async errors
  • Wrap critical widget subtrees in custom error boundary widgets that show fallback UI instead of red screens
  • In release mode: NEVER show stack traces to users — show user-friendly error messages only
  • 预发布/生产环境将错误上报至Crashlytics:
    FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError
  • 配置
    FlutterError.onError
    PlatformDispatcher.instance.onError
    捕获框架错误和异步错误
  • 为关键组件子树包裹自定义错误边界组件,展示兜底UI而非红屏错误
  • 生产环境:绝对不要向用户展示堆栈信息,仅展示友好的错误提示