后台播放能力已调通,介入部分细节优化

This commit is contained in:
2026-08-20 22:36:10 +08:00
parent f94cda4234
commit bb8e4caf48
2 changed files with 303 additions and 49 deletions
+114 -49
View File
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:media_kit/media_kit.dart';
//import 'package:audio_service/audio_service.dart' as audio_service;
import 'package:audio_service/audio_service.dart' as audio_service;
import 'package:permission_handler/permission_handler.dart';
import 'services/audio_service.dart';
@@ -9,6 +9,7 @@ import 'services/playback_service.dart';
import 'services/app_lifecycle_service.dart';
import 'services/webdav_service.dart';
import 'services/audio_player_handler.dart';
import 'services/app_lifecycle_manager.dart';
import 'pages/home_page.dart';
import 'pages/player_page.dart';
import 'pages/playlist_page.dart';
@@ -23,6 +24,9 @@ bool _appInitialized = false;
// ⭐ 全局缓存 Handler
AudioPlayerHandler? _audioHandler;
// ⭐ 全局缓存 LifecycleManager
final AppLifecycleManager lifecycleManager = AppLifecycleManager();
void main() async {
// ⭐ P0:防止重复初始化
if (_appInitialized) {
@@ -53,6 +57,10 @@ void main() async {
providers: [
ChangeNotifierProvider(create: (_) => AudioService()),
ChangeNotifierProvider(create: (_) => AppLifecycleService()),
// ⭐ 生命周期管理器
ChangeNotifierProvider<AppLifecycleManager>(
create: (_) => lifecycleManager,
),
Provider<AudioPlayerHandler>(create: (_) => _audioHandler!),
],
child: const QTPlayerApp(),
@@ -121,8 +129,14 @@ class QTPlayerApp extends StatefulWidget {
}
class _QTPlayerAppState extends State<QTPlayerApp> {
// ⭐ build 计数器(诊断用)
static int _buildCount = 0;
bool _isInitializing = false;
// ⭐ 保存生命周期监听器引用
void Function(AppLifecycleStatus)? _lifecycleListener;
// ============================================================
// 生命周期
// ============================================================
@@ -134,92 +148,143 @@ class _QTPlayerAppState extends State<QTPlayerApp> {
WidgetsBinding.instance.addPostFrameCallback((_) {
debugPrint('⏱️ T2 首帧回调: ${stopwatch.elapsedMilliseconds}ms');
// ⭐ 1. 初始化生命周期管理器
lifecycleManager.init();
// ⭐ 2. 绑定生命周期到播放器
_bindLifecycleToPlayback();
// ⭐ 3. 后台初始化
_startBackgroundInitialization();
});
}
@override
void dispose() {
// ⭐ 移除生命周期监听器
if (_lifecycleListener != null) {
lifecycleManager.removeListenerFromManager(_lifecycleListener!);
}
super.dispose();
}
// ============================================================
// 后台初始化(不阻塞首帧)
// 生命周期 → 播放器绑定
// ============================================================
void _bindLifecycleToPlayback() {
if (_lifecycleListener != null) {
lifecycleManager.removeListenerFromManager(_lifecycleListener!);
}
_lifecycleListener = (status) {
final audioService = context.read<AudioService>();
switch (status) {
case AppLifecycleStatus.paused:
case AppLifecycleStatus.inactive:
debugPrint('🎵 App 进入后台,播放继续');
break;
case AppLifecycleStatus.resumed:
debugPrint('🎵 App 回到前台');
break;
case AppLifecycleStatus.backgroundIdle:
debugPrint('🎵 长后台唤醒,检查播放状态');
break;
default:
break;
}
};
lifecycleManager.addListenerToManager(_lifecycleListener!);
}
// ============================================================
// 后台初始化(精细时间切片)
// ============================================================
Future<void> _startBackgroundInitialization() async {
if (_isInitializing) return;
_isInitializing = true;
final tStart = DateTime.now();
debugPrint('⏱️ T3 后台初始化开始');
// 1. PlaybackService(轻量级)
// ----- 1. PlaybackService -----
final t1 = DateTime.now();
try {
PlaybackService().init();
debugPrint('⏱️ T3.1 PlaybackService 初始化完成');
debugPrint('⏱️ T3.1 PlaybackService 完成: ${_elapsedMs(t1)}ms');
} catch (e) {
debugPrint('❌ PlaybackService 初始化失败: $e');
debugPrint('❌ PlaybackService 失败: $e');
}
// 2. ⭐ AudioService 暂时禁用(等 MainActivity 改为 AudioServiceActivity 后启用)
// await _initAudioService();
// 3. WebDAV
await _initWebDAV();
// 4. 通知权限
await _requestPermissions();
debugPrint('⏱️ T4 全部初始化完成');
}
// ════════════════════════════════════════════════════════════
// 子初始化方法
// ════════════════════════════════════════════════════════════
// ⭐ 暂时禁用,等 MainActivity 改为 AudioServiceActivity 后启用
// Future<void> _initAudioService() async {
// try {
// await audio_service.AudioService.init(
// builder: () => _audioHandler!,
// config: const audio_service.AudioServiceConfig(
// androidNotificationChannelId: 'com.example.qt_player.music',
// androidNotificationChannelName: '清听音乐播放',
// androidNotificationOngoing: true,
// androidStopForegroundOnPause: true,
// ),
// );
// debugPrint('✅ AudioService 初始化完成');
// } catch (e) {
// debugPrint('❌ AudioService 初始化失败: $e');
// }
// }
Future<void> _initWebDAV() async {
// ----- 2. WebDAV(只加载凭证) -----
final t2 = DateTime.now();
try {
final hasCred = await WebDAVService.instance.loadCredentials();
debugPrint(' WebDAV 加载完成, 已连接: $hasCred');
debugPrint('⏱️ T3.2 WebDAV 凭证加载完成: ${_elapsedMs(t2)}ms, 有凭证: $hasCred');
} catch (e) {
debugPrint('❌ WebDAV 加载失败: $e');
debugPrint('❌ WebDAV 凭证加载失败: $e');
}
}
Future<void> _requestPermissions() async {
// ----- 3. ⭐ AudioService(后台播放核心) -----
await _initAudioService();
// ----- 4. 通知权限 -----
final t3 = DateTime.now();
try {
if (await Permission.notification.isDenied) {
final status = await Permission.notification.request();
debugPrint('📢 通知权限状态: $status');
await Permission.notification.request();
debugPrint('⏱️ T3.3 通知权限完成: ${_elapsedMs(t3)}ms');
} else {
debugPrint('⏱️ T3.3 通知权限已授予: ${_elapsedMs(t3)}ms');
}
} catch (e) {
debugPrint('❌ 权限申请失败: $e');
}
final tEnd = DateTime.now();
debugPrint('⏱️ T4 全部初始化完成: ${tEnd.difference(tStart).inMilliseconds}ms');
}
// ============================================================
// ════════════════════════════════════════════════════════════
// ⭐ AudioService 初始化(后台播放核心)
// ════════════════════════════════════════════════════════════
Future<void> _initAudioService() async {
try {
await audio_service.AudioService.init(
builder: () => _audioHandler!,
config: const audio_service.AudioServiceConfig(
androidNotificationChannelId: 'com.example.qt_player.music',
androidNotificationChannelName: '清听音乐播放',
androidNotificationOngoing: true,
androidStopForegroundOnPause: true,
),
);
debugPrint('✅ AudioService 初始化完成');
} catch (e) {
debugPrint('❌ AudioService 初始化失败: $e');
}
}
// ════════════════════════════════════════════════════════════
// 辅助方法
// ════════════════════════════════════════════════════════════
String _elapsedMs(DateTime start) {
return '${DateTime.now().difference(start).inMilliseconds}';
}
// ════════════════════════════════════════════════════════════
// Build
// ============================================================
// ════════════════════════════════════════════════════════════
@override
Widget build(BuildContext context) {
debugPrint('⏱️ T1 build: ${stopwatch.elapsedMilliseconds}ms');
_buildCount++;
debugPrint(
'🎨 [QTPlayerApp] build #$_buildCount ${stopwatch.elapsedMilliseconds}ms');
// 监听歌曲变化,更新通知栏
final audioService = context.watch<AudioService>();