From 0493c1044f4ffedea1543ff82814cd3f8f08d9b1 Mon Sep 17 00:00:00 2001 From: wuqifeng <540416539@qq.com> Date: Sat, 27 Jul 2024 00:27:51 +0800 Subject: [PATCH] feat:带音乐点击防抖函数优化 --- lib/common/utils/action_with_music_controller.dart | 36 ------------------------------------ lib/common/utils/click_with_music_controller.dart | 45 +++++++++++++++++++++++++++++++++++++++++++++ lib/pages/section/bloc/section_bloc.dart | 18 +++++++++++------- lib/pages/section/section_page.dart | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------- 4 files changed, 110 insertions(+), 84 deletions(-) delete mode 100644 lib/common/utils/action_with_music_controller.dart create mode 100644 lib/common/utils/click_with_music_controller.dart diff --git a/lib/common/utils/action_with_music_controller.dart b/lib/common/utils/action_with_music_controller.dart deleted file mode 100644 index d04b234..0000000 --- a/lib/common/utils/action_with_music_controller.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../utils/audio_player_util.dart'; - -/// action前播放音乐控制类,维护状态做防抖处理 -/// todo 需要结合生命周期,尤其是在声明周期结束后及时中断,避免action泄漏 -class ActionWithMusicController { - ActionWithMusicController._privateConstructor(); - - static final ActionWithMusicController _instance = ActionWithMusicController._privateConstructor(); - - factory ActionWithMusicController() { - return _instance; - } - - bool _isPlaying = false; - - Future playMusicAndPerformAction(BuildContext context, - AudioPlayerUtilType audioType, Function action) async { - if (_isPlaying) return; - - _isPlaying = true; - - // Play the music - await AudioPlayerUtil.getInstance() - .playAudio(audioType); - - action(); - - _isPlaying = false; - } - - // void dispose() { - // _audioPlayer.dispose(); - // } -} \ No newline at end of file diff --git a/lib/common/utils/click_with_music_controller.dart b/lib/common/utils/click_with_music_controller.dart new file mode 100644 index 0000000..288302b --- /dev/null +++ b/lib/common/utils/click_with_music_controller.dart @@ -0,0 +1,45 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +import '../../utils/audio_player_util.dart'; +import '../../utils/log_util.dart'; + +/// action前播放音乐控制类,维护状态做防抖处理 +/// todo 需要结合生命周期,尤其是在声明周期结束后及时中断,避免action泄漏 +class ClickWithMusicController { + + static ClickWithMusicController? _instance; + + ClickWithMusicController._privateConstructor(); + + static ClickWithMusicController get instance => _instance ??= ClickWithMusicController._privateConstructor(); + + bool _isPlaying = false; + + ///@param action 可以是同步函数也可以是异步函数 + Future playMusicAndPerformAction(BuildContext context, + AudioPlayerUtilType audioType, FutureOr Function() action) async { + if (_isPlaying) return; + + _isPlaying = true; + Log.d("WQF playMusicAndPerformAction playAudio begin"); + + // Play the music + await AudioPlayerUtil.getInstance() + .playAudio(audioType); + + try { + await Future.sync(action); + } catch (e) { + Log.d('WQF playMusicAndPerformAction exception $e'); + } finally { + Log.d("WQF playMusicAndPerformAction playAudio end"); + _isPlaying = false; + } + } + + // void dispose() { + // _audioPlayer.dispose(); + // } +} \ No newline at end of file diff --git a/lib/pages/section/bloc/section_bloc.dart b/lib/pages/section/bloc/section_bloc.dart index 37617d4..f447fa8 100644 --- a/lib/pages/section/bloc/section_bloc.dart +++ b/lib/pages/section/bloc/section_bloc.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -57,7 +59,8 @@ class SectionBloc extends Bloc { on(_onEnterClass); on(_pageControllerChange); on((event, emit) async { - await AudioPlayerUtil.getInstance().playAudio(AudioPlayerUtilType.countWithMe); + await AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.countWithMe); }); } @@ -87,20 +90,21 @@ class SectionBloc extends Bloc { ///进入课程接口请求函数封装 ///onRequestEnterSuccess 接口请求成功后行为函数,比如跳转课程页面 - Future requestEnterClass(String courseLessonId, Function onRequestEnterSuccess, - {Function? onRequestEnterFailed}) async { + Future requestEnterClass( + String courseLessonId, FutureOr Function() onRequestEnterSuccess, + {FutureOr Function(Object)? onRequestEnterFailed}) async { await loading(() async { try { await ListenDao.enterClass(courseLessonId); - onRequestEnterSuccess(); + await Future.sync(onRequestEnterSuccess); } catch (e) { if (e is ApiException) { - showToast(e.message ?? '请求失败,请检查网络连接'); + showToast('进入课堂失败 ${e.message}'); } else { - showToast('$e'); + showToast('进入课堂失败 $e'); } if (onRequestEnterFailed != null) { - onRequestEnterFailed(e); + await Future.sync(onRequestEnterFailed(e) as FutureOr Function()); } } }); diff --git a/lib/pages/section/section_page.dart b/lib/pages/section/section_page.dart index 424d562..2ea9712 100644 --- a/lib/pages/section/section_page.dart +++ b/lib/pages/section/section_page.dart @@ -4,7 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:nested_scroll_views/material.dart'; import 'package:wow_english/common/core/user_util.dart'; -import 'package:wow_english/common/utils/action_with_music_controller.dart'; +import 'package:wow_english/common/utils/click_with_music_controller.dart'; import 'package:wow_english/models/course_unit_entity.dart'; import 'package:wow_english/pages/section/section_type.dart'; import 'package:wow_english/pages/section/widgets/section_item.dart'; @@ -15,6 +15,7 @@ import 'package:wow_english/utils/audio_player_util.dart'; import 'package:wow_english/utils/toast_util.dart'; import '../../models/course_section_entity.dart'; +import '../../utils/log_util.dart'; import 'bloc/section_bloc.dart'; import 'courese_module_model.dart'; @@ -56,30 +57,34 @@ class _SectionPageView extends StatelessWidget { @override Widget build(BuildContext context) { final bloc = BlocProvider.of(context); - final controller = ActionWithMusicController(); + final clickController = ClickWithMusicController.instance; return BlocListener( listener: (context, state) async { if (state is RequestEnterClassState) { - if (state.courseType == SectionType.song.value || - state.courseType == SectionType.video.value) { - var title = - state.courseType == SectionType.song.value ? 'song' : 'video'; + final courseType = state.courseType; + final courseLessonId = state.courseLessonId; + if (courseType == SectionType.song.value || + courseType == SectionType.video.value) { + final title = + courseType == SectionType.song.value ? 'song' : 'video'; + final AudioPlayerUtilType audioType; - AudioPlayerUtilType audioType; ///儿歌/视频类型 - if (state.courseType == SectionType.song.value) { + if (courseType == SectionType.song.value) { audioType = AudioPlayerUtilType.musicTime; } else { audioType = AudioPlayerUtilType.videoTime; } - controller.playMusicAndPerformAction(context, audioType, () async { + clickController.playMusicAndPerformAction(context, audioType, + () async { ///播放音乐->调进入课程接口->跳转课程页面 - bloc.requestEnterClass(state.courseLessonId, () { + await bloc.requestEnterClass(courseLessonId, () { + Log.d("WQF request finish"); pushNamed(AppRouteName.lookVideo, arguments: { 'videoUrl': null, 'title': title, - 'courseLessonId': state.courseLessonId, + 'courseLessonId': courseLessonId, 'isTopic': true }).then((value) { if (value != null) { @@ -93,50 +98,58 @@ class _SectionPageView extends StatelessWidget { AudioPlayerUtil.getInstance() .playAudio(AudioPlayerUtilType.countWithMe); }); + }, onRequestEnterFailed: (error) { + Log.d("WQF requestEnterClass failed $error"); }); }); return; } - if (state.courseType == SectionType.pictureBook.value) { + if (courseType == SectionType.pictureBook.value) { //绘本 - controller.playMusicAndPerformAction( + clickController.playMusicAndPerformAction( context, AudioPlayerUtilType.readingTime, () async { - pushNamed(AppRouteName.reading, - arguments: {'courseLessonId': state.courseLessonId}) - .then((value) { - if (value != null) { - Map dataMap = value as Map; - bloc.add(RequestEndClassEvent( - dataMap['courseLessonId']!, - dataMap['isCompleted'], - currentStep: dataMap['currentStep'], - autoNextSection: dataMap['nextSection'], - )); - AudioPlayerUtil.getInstance() - .playAudio(AudioPlayerUtilType.countWithMe); - } + await bloc.requestEnterClass(courseLessonId, () { + pushNamed(AppRouteName.reading, + arguments: {'courseLessonId': courseLessonId}) + .then((value) { + if (value != null) { + Map dataMap = + value as Map; + bloc.add(RequestEndClassEvent( + dataMap['courseLessonId']!, + dataMap['isCompleted'], + currentStep: dataMap['currentStep'], + autoNextSection: dataMap['nextSection'], + )); + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.countWithMe); + } + }); }); }); return; } - if (state.courseType == SectionType.practice.value) { + if (courseType == SectionType.practice.value) { //练习 - controller.playMusicAndPerformAction( + clickController.playMusicAndPerformAction( context, AudioPlayerUtilType.quizTime, () async { - pushNamed(AppRouteName.topicPic, - arguments: {'courseLessonId': state.courseLessonId}) - .then((value) { - if (value != null) { - Map dataMap = value as Map; - bloc.add(RequestEndClassEvent( - dataMap['courseLessonId']!, dataMap['isCompleted'], - currentStep: dataMap['currentStep'], - autoNextSection: dataMap['nextSection'])); - } - AudioPlayerUtil.getInstance() - .playAudio(AudioPlayerUtilType.countWithMe); + await bloc.requestEnterClass(courseLessonId, () { + pushNamed(AppRouteName.topicPic, + arguments: {'courseLessonId': courseLessonId}) + .then((value) { + if (value != null) { + Map dataMap = + value as Map; + bloc.add(RequestEndClassEvent( + dataMap['courseLessonId']!, dataMap['isCompleted'], + currentStep: dataMap['currentStep'], + autoNextSection: dataMap['nextSection'])); + } + AudioPlayerUtil.getInstance() + .playAudio(AudioPlayerUtilType.countWithMe); + }); }); }); return; -- libgit2 0.22.2