From 8a556f764036db1d7164b9afd3828bdf4f034e8d Mon Sep 17 00:00:00 2001 From: wuqifeng <540416539@qq.com> Date: Mon, 29 Jul 2024 00:02:04 +0800 Subject: [PATCH] feat:性能优化-首页'wow精选'增加生命周期感知,适时暂停动画 --- lib/app/app.dart | 4 +++- lib/pages/home/widgets/ShakeImage.dart | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 186 insertions(+), 20 deletions(-) diff --git a/lib/app/app.dart b/lib/app/app.dart index 93a4b55..eb43b6b 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -12,6 +12,8 @@ import 'package:wow_english/route/route.dart'; import '../route/custom_navigator_observer.dart'; +final RouteObserver customerRouteObserver = CustomNavigatorObserver(); + class App extends StatelessWidget { const App([this._navigatorObserver]); @@ -51,7 +53,7 @@ class App extends StatelessWidget { navigatorObservers: [ // 带入ApmNavigatorObserver实例用于路由监听 // 如果不带入SDK监听器将无法获知页面(PV)入栈退栈行为,错误率(Dart异常数/FlutterPV次数)将异常攀升。 - _navigatorObserver ?? ApmNavigatorObserver.singleInstance, CustomNavigatorObserver() + _navigatorObserver ?? ApmNavigatorObserver.singleInstance, customerRouteObserver ], ), )), diff --git a/lib/pages/home/widgets/ShakeImage.dart b/lib/pages/home/widgets/ShakeImage.dart index 9d49751..cd1fa13 100644 --- a/lib/pages/home/widgets/ShakeImage.dart +++ b/lib/pages/home/widgets/ShakeImage.dart @@ -1,9 +1,13 @@ - import 'dart:async'; +import 'dart:ui'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/scheduler.dart'; import 'package:wow_english/common/extension/string_extension.dart'; +import '../../../app/app.dart'; +import '../../../utils/log_util.dart'; + ///带左右摇晃的wow封面 class ShakeImage extends StatefulWidget { const ShakeImage({super.key}); @@ -12,16 +16,40 @@ class ShakeImage extends StatefulWidget { _ShakeImageState createState() => _ShakeImageState(); } -class _ShakeImageState extends State with SingleTickerProviderStateMixin, - WidgetsBindingObserver { +class _ShakeImageState extends State + with SingleTickerProviderStateMixin, WidgetsBindingObserver, RouteAware { late AnimationController _controller; late Animation _animation; late Timer _timer; + late final AppLifecycleListener appLifecycleListener; + static const TAG = 'ShakeImage'; @override void initState() { + var lifecycleState = SchedulerBinding.instance.lifecycleState; + printLog( + 'lifecycleState:$lifecycleState'); // lifecycleState:AppLifecycleState.resumed + + appLifecycleListener = AppLifecycleListener( + onStateChange: onStateChange, + onResume: onResume, + onInactive: onInactive, + onHide: onHide, + onShow: onShow, + onPause: onPause, + onRestart: onRestart, + onDetach: onDetach, + onExitRequested: onExitRequested, + ); + super.initState(); WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance.addPostFrameCallback((_) { + final route = ModalRoute.of(context); + if (route is PageRoute) { + customerRouteObserver.subscribe(this, route); + } + }); _controller = AnimationController( duration: const Duration(seconds: 2), @@ -29,21 +57,37 @@ class _ShakeImageState extends State with SingleTickerProviderStateM ); _animation = TweenSequence([ - TweenSequenceItem(tween: Tween(begin: 0.0, end: 0.05).chain(CurveTween(curve: Curves.easeInOut)), weight: 1), - TweenSequenceItem(tween: Tween(begin: 0.05, end: -0.1).chain(CurveTween(curve: Curves.easeInOut)), weight: 1), - TweenSequenceItem(tween: Tween(begin: -0.1, end: 0.2).chain(CurveTween(curve: Curves.easeInOut)), weight: 1), - TweenSequenceItem(tween: Tween(begin: 0.2, end: -0.2).chain(CurveTween(curve: Curves.easeInOut)), weight: 1), - TweenSequenceItem(tween: Tween(begin: -0.2, end: 0.1).chain(CurveTween(curve: Curves.easeInOut)), weight: 1), - TweenSequenceItem(tween: Tween(begin: 0.1, end: -0.05).chain(CurveTween(curve: Curves.easeInOut)), weight: 1), - TweenSequenceItem(tween: Tween(begin: -0.05, end: 0.0).chain(CurveTween(curve: Curves.easeInOut)), weight: 1), + TweenSequenceItem( + tween: Tween(begin: 0.0, end: 0.05) + .chain(CurveTween(curve: Curves.easeInOut)), + weight: 1), + TweenSequenceItem( + tween: Tween(begin: 0.05, end: -0.1) + .chain(CurveTween(curve: Curves.easeInOut)), + weight: 1), + TweenSequenceItem( + tween: Tween(begin: -0.1, end: 0.2) + .chain(CurveTween(curve: Curves.easeInOut)), + weight: 1), + TweenSequenceItem( + tween: Tween(begin: 0.2, end: -0.2) + .chain(CurveTween(curve: Curves.easeInOut)), + weight: 1), + TweenSequenceItem( + tween: Tween(begin: -0.2, end: 0.1) + .chain(CurveTween(curve: Curves.easeInOut)), + weight: 1), + TweenSequenceItem( + tween: Tween(begin: 0.1, end: -0.05) + .chain(CurveTween(curve: Curves.easeInOut)), + weight: 1), + TweenSequenceItem( + tween: Tween(begin: -0.05, end: 0.0) + .chain(CurveTween(curve: Curves.easeInOut)), + weight: 1), ]).animate(_controller); - Timer(const Duration(seconds: 1), () { - _controller.forward(from: 0.0); - _timer = Timer.periodic(const Duration(seconds: 4), (Timer timer) { - _controller.forward(from: 0.0); - }); - }); + printLog("--initState"); // _controller.addStatusListener((status) { // if (status == AnimationStatus.completed) { @@ -54,6 +98,67 @@ class _ShakeImageState extends State with SingleTickerProviderStateM // }); } + void _startAnimation() { + Timer(const Duration(seconds: 1), () { + _controller.forward(from: 0.0); + _timer = Timer.periodic(const Duration(seconds: 4), (Timer timer) { + _controller.forward(from: 0.0); + }); + }); + printLog('_startAnimation'); + } + + void _stopAnimation() { + _timer.cancel(); + printLog('_stopAnimation'); + } + + ///进下一页 + @override + void didPushNext() { + super.didPushNext(); + printLog('--didPushNext'); + _stopAnimation(); + } + + ///下一个页面退回到当前页 + @override + void didPopNext() { + printLog('--didPopNext'); + super.didPopNext(); + _startAnimation(); + } + + ///进入到当前页,在initState之后执行 + @override + void didPush() { + super.didPush(); + printLog('--didPush'); + _startAnimation(); + } + + ///退出当前页到上一页,监听导航栈中的路由被弹出(即当前页面被移除)的事件 + @override + void didPop() { + super.didPop(); + printLog('--didPop'); + _stopAnimation(); + } + + @override + Future didPushRouteInformation(RouteInformation routeInformation) { + printLog('--didPushRouteInformation routeInformation=$routeInformation'); + return super.didPushRouteInformation(routeInformation); + } + + ///系统导航栏上的后退按钮(Android)或物理返回按钮被按下时调用,这个方法允许你拦截和处理系统的返回操作。 + @override + Future didPopRoute() { + printLog('--didPopRoute'); + return super.didPopRoute(); + } + + ///前后台切换 @override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.paused) { @@ -65,6 +170,8 @@ class _ShakeImageState extends State with SingleTickerProviderStateM @override void dispose() { + printLog('dispose'); + customerRouteObserver.unsubscribe(this); WidgetsBinding.instance.removeObserver(this); _controller.dispose(); _timer.cancel(); @@ -82,9 +189,66 @@ class _ShakeImageState extends State with SingleTickerProviderStateM child: child, ); }, - child: Image.asset('xe_shop'.assetPng, - width: 153), + child: Image.asset('xe_shop'.assetPng, width: 153), ), ); } -} \ No newline at end of file + + /// 监听状态 + onStateChange(AppLifecycleState state) { + printLog('app_state:$state'); + } + + // =============================== 根据App状态的产生的各种回调 =============================== + + /// 可见,并且可以响应用户操作时的回调 + /// 比如应用从后台调度到前台时,在 onShow() 后面 执行 + /// 注意:这个回调,初始化时 不执行 + onResume() { + printLog('---onResume'); + _startAnimation(); + } + + /// 可见,但无法响应用户操作时的回调 + onInactive() { + printLog('---onInactive'); + } + + /// 隐藏时的回调 + onHide() { + printLog('---onHide'); + } + + /// 显示时的回调,应用从后台调度到前台时 + onShow() { + printLog('---onShow'); + } + + /// 暂停时的回调(后台) + onPause() { + printLog('---onPause'); + _stopAnimation(); + } + + /// 暂停后恢复时的回调 + onRestart() { + printLog('---onRestart'); + } + + /// 这两个回调,不是所有平台都支持, + /// 当退出 并将所有视图与引擎分离时的回调(IOS 支持,Android 不支持) + onDetach() { + printLog('---onDetach'); + } + + /// 在退出程序时,发出询问的回调(IOS、Android 都不支持) + /// 响应 [AppExitResponse.exit] 将继续终止,响应 [AppExitResponse.cancel] 将取消终止。 + Future onExitRequested() async { + printLog('---onExitRequested'); + return AppExitResponse.exit; + } + + void printLog(String msg) { + // Log.d('$TAG $msg'); + } +} -- libgit2 0.22.2