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调试布局问题,识别不必要的组件重绘
  • 使用性能浮层
    showPerformanceOverlay: true
    )监控帧率
  • 使用时间线视图识别卡顿,目标单帧耗时≤16ms(60fps)
  • 使用内存视图检测内存泄漏,监控内存分配模式
  • 开发阶段使用网络分析器查看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
  • 所有控制器、订阅对象、
    Timer
    AnimationController
    都要在
    dispose()
    方法中销毁
  • initState()
    中使用
    late
    初始化对象,绝对不要内联初始化需要销毁的对象
  • 缓存场景使用
    WeakReference
    ,避免阻止垃圾回收
  • 使用DevTools的内存标签页分析内存,注意持续增长的内存分配情况
  • 警惕常见泄漏场景:未销毁的监听器、捕获了
    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而不是红屏报错
  • 生产环境绝对不要向用户展示堆栈信息,仅展示友好的错误提示