Files
QingTing-Player/lib/services/app_lifecycle_manager.dart
T

187 lines
5.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// lib/services/app_lifecycle_manager.dart
import 'package:flutter/material.dart';
/// App 生命周期状态(扩展了 Flutter 原生状态)
enum AppLifecycleStatus {
/// 应用正在启动(初始化阶段)
launching,
/// 应用在前台,用户可交互
resumed,
/// 应用在前台但不可交互(如:来电、系统弹窗)
inactive,
/// 应用在后台
paused,
/// 应用即将被销毁
detached,
/// 应用已进入后台且播放停止(自定义,用于播放策略)
backgroundIdle,
}
/// App 生命周期管理器
///
/// 职责:
/// 1. 统一监听 Flutter 的 AppLifecycleState
/// 2. 管理播放器在前后台的行为
/// 3. 管理渲染调度器的运行状态
/// 4. 管理 WebDAV 的缓存策略
class AppLifecycleManager extends ChangeNotifier {
static final AppLifecycleManager _instance = AppLifecycleManager._internal();
factory AppLifecycleManager() => _instance;
AppLifecycleManager._internal();
// ---- 当前状态 ----
AppLifecycleStatus _status = AppLifecycleStatus.launching;
AppLifecycleStatus get status => _status;
// ---- 上次进入后台的时间 ----
DateTime? _backgroundedAt;
DateTime? get backgroundedAt => _backgroundedAt;
// ---- 是否在后台 ----
bool get isInBackground =>
_status == AppLifecycleStatus.paused ||
_status == AppLifecycleStatus.inactive ||
_status == AppLifecycleStatus.detached;
bool get isInForeground => _status == AppLifecycleStatus.resumed;
// ---- 后台时长 ----
Duration get backgroundDuration {
if (_backgroundedAt == null) return Duration.zero;
return DateTime.now().difference(_backgroundedAt!);
}
// ---- 是否处于"长后台"(超过 5 分钟) ----
bool get isLongBackground => backgroundDuration > const Duration(minutes: 5);
// ---- 监听器 ----
final List<void Function(AppLifecycleStatus)> _listeners = [];
// ---- Flutter 原生生命周期订阅 ----
late final WidgetsBindingObserver _observer;
bool _isObserving = false;
// ---- 初始化 ----
void init() {
if (_isObserving) return;
_isObserving = true;
_observer = _AppLifecycleObserver(this);
WidgetsBinding.instance.addObserver(_observer);
// 获取初始状态
_updateStatus(AppLifecycleStatus.resumed);
debugPrint('📱 AppLifecycleManager 已初始化');
}
// ---- 状态更新 ----
void _handleNativeState(AppLifecycleState state) {
final newStatus = _convertNativeState(state);
// 状态变化时更新
if (newStatus != _status) {
_updateStatus(newStatus);
}
// 记录进入后台的时间
if (newStatus == AppLifecycleStatus.paused ||
newStatus == AppLifecycleStatus.inactive) {
if (_backgroundedAt == null) {
_backgroundedAt = DateTime.now();
debugPrint('📱 App 进入后台: ${_backgroundedAt}');
}
}
// 回到前台时,如果是长后台,触发通知
if (newStatus == AppLifecycleStatus.resumed) {
if (_backgroundedAt != null) {
final duration = backgroundDuration;
debugPrint('📱 App 回到前台,后台时长: ${duration.inMinutes}分钟');
_backgroundedAt = null;
// 如果是长后台,通知监听器做重连等操作
if (duration > const Duration(minutes: 5)) {
_notifyListeners(AppLifecycleStatus.backgroundIdle);
}
}
}
}
void _updateStatus(AppLifecycleStatus newStatus) {
final oldStatus = _status;
_status = newStatus;
debugPrint('📱 生命周期状态变化: $oldStatus$newStatus');
notifyListeners();
_notifyListeners(newStatus);
}
AppLifecycleStatus _convertNativeState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
return AppLifecycleStatus.resumed;
case AppLifecycleState.inactive:
return AppLifecycleStatus.inactive;
case AppLifecycleState.paused:
return AppLifecycleStatus.paused;
case AppLifecycleState.detached:
return AppLifecycleStatus.detached;
default:
return AppLifecycleStatus.paused;
}
}
// ---- 自定义监听器管理 ----
void addListenerToManager(void Function(AppLifecycleStatus) listener) {
_listeners.add(listener);
}
void removeListenerFromManager(void Function(AppLifecycleStatus) listener) {
_listeners.remove(listener);
}
void _notifyListeners(AppLifecycleStatus status) {
for (final listener in _listeners) {
try {
listener(status);
} catch (e) {
debugPrint('❌ 生命周期监听器执行失败: $e');
}
}
}
// ---- 检查是否需要重新连接 WebDAV ----
bool get shouldRecheckWebDAV {
if (!isInForeground) return false;
if (_backgroundedAt == null) return false;
return isLongBackground;
}
// ---- 释放 ----
void dispose() {
if (_isObserving) {
WidgetsBinding.instance.removeObserver(_observer);
_isObserving = false;
}
_listeners.clear();
super.dispose();
}
}
/// 内部观察者(绑定 WidgetsBinding
class _AppLifecycleObserver extends WidgetsBindingObserver {
final AppLifecycleManager _manager;
_AppLifecycleObserver(this._manager);
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
_manager._handleNativeState(state);
}
}