Commit 523864dd18878775b430d258c0b8a47db684dc46

Authored by 吴启风
1 parent b2af9c1c

feat:音频播放单例增加声明周期感知

lib/pages/games/bloc.dart
... ... @@ -44,7 +44,7 @@ class GamesBloc extends Bloc<GamesEvent, GamesState> {
44 44 }
45 45  
46 46 void _gotoGamePage(GotoGamePageEvent event, Emitter<GamesState> emit) async {
47   - AudioPlayerUtil.getInstance().pause();
  47 + await AudioPlayerUtil.getInstance().pause();
48 48 try {
49 49 _methodChannel = const MethodChannel('wow_english/game_method_channel');
50 50 await _methodChannel
... ...
lib/pages/section/section_page.dart
... ... @@ -59,7 +59,7 @@ class _SectionPageView extends StatelessWidget {
59 59 Widget build(BuildContext context) {
60 60 final bloc = BlocProvider.of<SectionBloc>(context);
61 61 return BlocListener<SectionBloc, SectionState>(
62   - listener: (context, state) {
  62 + listener: (context, state) async {
63 63 if (state is RequestVideoLessonState) {
64 64 final videoUrl = bloc.processEntity?.videos?.videoUrl ?? '';
65 65 var title = '';
... ... @@ -103,40 +103,36 @@ class _SectionPageView extends StatelessWidget {
103 103 ///视频类型
104 104 ///获取视频课程内容
105 105 if (state.courseType == 1) {
106   - AudioPlayerUtil.getInstance()
  106 + await AudioPlayerUtil.getInstance()
107 107 .playAudio(AudioPlayerUtilType.musicTime);
108 108 } else {
109   - AudioPlayerUtil.getInstance()
  109 + await AudioPlayerUtil.getInstance()
110 110 .playAudio(AudioPlayerUtilType.videoTime);
111 111 }
112   - Future.delayed(const Duration(seconds: 1), () {
113   - bloc.add(RequestVideoLessonEvent(
114   - state.courseLessonId, state.courseType));
115   - });
  112 + bloc.add(RequestVideoLessonEvent(
  113 + state.courseLessonId, state.courseType));
116 114  
117 115 return;
118 116 }
119 117  
120 118 if (state.courseType == SectionType.pictureBook.value) {
121   - AudioPlayerUtil.getInstance()
  119 + await AudioPlayerUtil.getInstance()
122 120 .playAudio(AudioPlayerUtilType.readingTime);
123   - Future.delayed(const Duration(seconds: 1), () {
124   - //绘本
125   - pushNamed(AppRouteName.reading,
126   - arguments: {'courseLessonId': state.courseLessonId})
127   - .then((value) {
128   - if (value != null) {
129   - Map<String, dynamic> dataMap = value as Map<String, dynamic>;
130   - bloc.add(RequestEndClassEvent(
131   - dataMap['courseLessonId']!,
132   - dataMap['isCompleted'],
133   - currentStep: dataMap['currentStep'],
134   - autoNextSection: dataMap['nextSection'],
135   - ));
136   - AudioPlayerUtil.getInstance()
137   - .playAudio(AudioPlayerUtilType.countWithMe);
138   - }
139   - });
  121 + //绘本
  122 + pushNamed(AppRouteName.reading,
  123 + arguments: {'courseLessonId': state.courseLessonId})
  124 + .then((value) {
  125 + if (value != null) {
  126 + Map<String, dynamic> dataMap = value as Map<String, dynamic>;
  127 + bloc.add(RequestEndClassEvent(
  128 + dataMap['courseLessonId']!,
  129 + dataMap['isCompleted'],
  130 + currentStep: dataMap['currentStep'],
  131 + autoNextSection: dataMap['nextSection'],
  132 + ));
  133 + AudioPlayerUtil.getInstance()
  134 + .playAudio(AudioPlayerUtilType.countWithMe);
  135 + }
140 136 });
141 137  
142 138 return;
... ... @@ -144,22 +140,20 @@ class _SectionPageView extends StatelessWidget {
144 140  
145 141 if (state.courseType == SectionType.practice.value) {
146 142 //练习
147   - AudioPlayerUtil.getInstance()
  143 + await AudioPlayerUtil.getInstance()
148 144 .playAudio(AudioPlayerUtilType.quizTime);
149   - Future.delayed(const Duration(seconds: 1), () {
150   - pushNamed(AppRouteName.topicPic,
151   - arguments: {'courseLessonId': state.courseLessonId})
152   - .then((value) {
153   - if (value != null) {
154   - Map<String, dynamic> dataMap = value as Map<String, dynamic>;
155   - bloc.add(RequestEndClassEvent(
156   - dataMap['courseLessonId']!, dataMap['isCompleted'],
157   - currentStep: dataMap['currentStep'],
158   - autoNextSection: dataMap['nextSection']));
159   - }
160   - AudioPlayerUtil.getInstance()
161   - .playAudio(AudioPlayerUtilType.countWithMe);
162   - });
  145 + pushNamed(AppRouteName.topicPic,
  146 + arguments: {'courseLessonId': state.courseLessonId})
  147 + .then((value) {
  148 + if (value != null) {
  149 + Map<String, dynamic> dataMap = value as Map<String, dynamic>;
  150 + bloc.add(RequestEndClassEvent(
  151 + dataMap['courseLessonId']!, dataMap['isCompleted'],
  152 + currentStep: dataMap['currentStep'],
  153 + autoNextSection: dataMap['nextSection']));
  154 + }
  155 + AudioPlayerUtil.getInstance()
  156 + .playAudio(AudioPlayerUtilType.countWithMe);
163 157 });
164 158 return;
165 159 }
... ...
lib/utils/audio_player_util.dart
1 1 import 'package:audioplayers/audioplayers.dart';
  2 +import 'package:flutter/cupertino.dart';
2 3 import 'package:wow_english/common/extension/string_extension.dart';
3 4  
4 5 enum AudioPlayerUtilType {
... ... @@ -18,15 +19,18 @@ enum AudioPlayerUtilType {
18 19 final String path;
19 20 }
20 21  
21   -class AudioPlayerUtil {
  22 +class AudioPlayerUtil extends WidgetsBindingObserver {
22 23 static AudioPlayerUtil? _instance;
23   - late AudioPlayer audioPlayer;
  24 + late AudioPlayer _audioPlayer;
24 25 late AudioPlayerUtilType currentType;
  26 + bool _wasPlaying = false;
25 27  
26 28 // 私有构造函数
27 29 AudioPlayerUtil._internal() {
28   - audioPlayer = AudioPlayer();
29   - audioPlayer.onPlayerStateChanged.listen((event) async {
  30 + // 监听应用生命周期
  31 + WidgetsBinding.instance.addObserver(this);
  32 + _audioPlayer = AudioPlayer();
  33 + _audioPlayer.onPlayerStateChanged.listen((event) async {
30 34 if (event == PlayerState.completed) {
31 35 // 播放结束再次播放
32 36 if (currentType == AudioPlayerUtilType.inMyTummy) {
... ... @@ -56,26 +60,46 @@ class AudioPlayerUtil {
56 60 Future<void> playAudio(AudioPlayerUtilType type) async {
57 61 currentType = type;
58 62 String path = type.path;
59   - await audioPlayer.play(AssetSource(path.assetMp3), volume: 0.5);
60   - await audioPlayer.onPlayerComplete.first;
  63 + await _audioPlayer.play(AssetSource(path.assetMp3), volume: 0.5);
  64 + await _audioPlayer.onPlayerComplete.first;
61 65 }
62 66  
63 67 // stop
64   - void stop() {
65   - audioPlayer.stop();
  68 + Future<void> stop() async {
  69 + _audioPlayer.stop();
66 70 }
67 71  
68 72 // pause
69   - void pause() {
70   - if (audioPlayer.state == PlayerState.playing) {
71   - audioPlayer.pause();
  73 + Future<void> pause() async {
  74 + if (_audioPlayer.state == PlayerState.playing) {
  75 + _audioPlayer.pause();
72 76 }
73 77 }
74 78  
75 79 // resume
76   - void resume() {
77   - if (audioPlayer.state == PlayerState.paused) {
78   - audioPlayer.resume();
  80 + Future<void> resume() async {
  81 + if (_audioPlayer.state == PlayerState.paused) {
  82 + _audioPlayer.resume();
79 83 }
80 84 }
  85 +
  86 + @override
  87 + void didChangeAppLifecycleState(AppLifecycleState state) async {
  88 + if (state == AppLifecycleState.paused) {
  89 + if (_audioPlayer.state == PlayerState.playing) {
  90 + _wasPlaying = true;
  91 + await pause();
  92 + };
  93 + } else if (state == AppLifecycleState.resumed) {
  94 + if (_wasPlaying == true) {
  95 + _wasPlaying = false;
  96 + await resume();
  97 + }
  98 + }
  99 + }
  100 +
  101 + void dispose() {
  102 + _audioPlayer.dispose();
  103 + WidgetsBinding.instance.removeObserver(this);
  104 + }
81 105 }
... ...