跳到主要内容

状态管理

回放页的状态通过双 Model 分层:PlaybackSession 管理高频播放器状态,ReviewDetailData 管理低频页面数据。两者均继承 ChangeNotifier,position 额外使用 ValueNotifier 独立高频通知。

双 Model 分层

PlaybackSession (高频交互状态)
├── position: ValueNotifier<Duration> ← ~10Hz,独立通知
├── isPlaying, isScrubbing ← ChangeNotifier
├── driveSource ← 识别 seek 来源
├── selectedDotId / selectedClipId ← 选中态
└── mode: all / highlight ← 时间轴模式

ReviewDetailData (低频数据状态)
├── dotRecords / dotCounts ← 打点列表和统计
├── clipRecords ← 剪辑片段
├── videoDuration / startTime ← 视频元数据
├── alignOffsetMs / recordType ← 对齐信息
└── filter: TimelineFilter ← 筛选条件

为什么分两个 Model?

维度PlaybackSessionReviewDetailData
更新频率~10Hz(播放中)用户操作时(编辑/删除/筛选)
驱动源播放器回调/用户拖拽DB 加载/用户编辑
监听方TimelineProgressTrack, VideoPreviewCardEventsCard, TimelineToolbar, StatsCard
独立性不依赖 Data不依赖 Session

如果合并为一个 Model,position ~10Hz 更新会触发所有监听方重建(包括事件列表),造成严重性能问题。

PlaybackDriveSource

enum PlaybackDriveSource {
player, // 播放器自然推进(不触发 UI 联动)
scrubbing, // 用户拖拽进度条
eventTap, // 点击事件卡片(前移 5s + 自动播放)
markerTap, // 点击时间轴 marker(前移 5s + 自动播放)
clipTap, // 点击片段区间
seekExternal, // 外部 seek(上/下一条按钮)
}

作用:不同 source 有不同的 UI 联动规则,例如 eventTap 会自动播放,player 不会更新选中态。

监听模式

// 高频:ValueListenableBuilder(仅重绘 Painter)
ValueListenableBuilder<Duration>(
valueListenable: session.position,
builder: (_, pos, __) => CustomPaint(painter: _ProgressMarkerPainter(pos)),
)

// 低频:addListener(setState 或局部更新)
session.addListener(_onSessionChanged);
data.addListener(_onDataChanged);

全局单例服务

服务模式用途
VideoClipTaskManager静态单例跨页面剪辑任务管理
FavoriteService静态单例 + ValueNotifier收藏缓存 + 变更通知
BackgroundCopyService静态单例后台视频拷贝
AuthService静态单例 + Stream登录状态广播

相关文档