如何在后台运行时钟定时器的Flutter?

c7rzv4ha  于 2022-12-27  发布在  Flutter
关注(0)|答案(5)|浏览(551)

我试图创建一个计时器应用程序,其中有多个倒计时计时器的不同任务。问题,我面临的是,如果我启动一个计时器,并按下返回按钮,计时器停止。所以我想,该计时器运行,直到它被暂停或计时器结束,并提醒用户或应用程序被摧毁。帮助我如何才能做到这一点使用Flutter?我也使用sql-lite来存储所有计时器。

mlnl4t2r

mlnl4t2r1#

啊,后台任务!Dart(Flutter使用的语言)是单线程的。

single-threaded是什么意思?

单线程语言,如Dart,有一个事件循环,这意味着Dart逐行运行代码(除非你使用Futures,但在这种情况下,这对你没有帮助),它注册像点击按钮这样的事件,并等待用户按下它们,等等。

我推荐这篇关于单线程的文章和视频:

https://medium.com/dartlang/dart-asynchronous-programming-isolates-and-event-loops-bffc3e296a6a
https://www.youtube.com/watch?v=vl_AaCgudcY&feature=emb_logo
无论如何,解决这个问题的方法(如上面的文章和视频中所提到的)是隔离。当你在Dart中创建一个隔离时,它会启动另一个线程来执行繁重的任务或只是在应用可能处于焦点或不处于焦点时执行一些任务。这样,主线程可以加载UI之类的东西,而在另一个线程中,它会处理你放入其中的其他东西,从而提高应用的性能。

它与您的问题有何关系?

您可以使用分离菌株在应用后台执行任务(打开或未打开)。
本质上,它使用隔离内部的Timer.periodic来执行任务,这非常适合您的场景。

rdlzhqv9

rdlzhqv92#

隔离不会解决这个问题。即使隔离得到暂停的操作系统时,应用程序在后台。我已经尝试过(在Android10定时器运行约100秒之前,它得到暂停的系统)。
对于您的问题,Android_Alarm_Manager包似乎是解决方案。但它只支持Android。还没有iOS支持

ut6juiuv

ut6juiuv3#

我也遇到过类似的问题。分离菌株无法解决这个问题,因为分离菌株生命周期也与主分离菌株(ui线程)相关联。我创建了一个变通方案,即我使用了dateTime属性,因此如果用户选择30分钟,最终的日期时间将变为Date time.now(持续时间(分钟:30));定时器周期函数,每分钟运行一次,查找最终日期时间和www.example.com()之间的差异datetime.now,因此即使操作系统在后台应用程序托盘中关闭了你的应用程序,当你重新打开应用程序时,时间会自动更新为变化。我还使用了flutter通知包,在定时器值变为零时提醒用户

i34xakig

i34xakig4#

我曾在一个Flutter项目与确切的情况下,你所描述的。
让我先告诉你,如上所述的隔离程序在这里不适用。当你的应用不在前台时,隔离程序似乎会暂停。操作系统为什么/何时删除后台隔离程序并不是一个单一的原因- Android和iOS实施ML驱动的进程管理程序,这些程序会删除线程以优化电池寿命、使用等。
我使用了一个相当初级的方法 shared_preferences。(我需要让我的计时器继续运行,即使应用程序完全从应用程序切换器关闭,也就是说,不在后台或前台)。以下是我所做的:
当应用程序处于前台并且计时器启动时,我会监听Flutter的生命周期钩子,以了解状态变化。(删除或移到B/g),我将计时器值保存在 shared_preferences 中。当应用再次处于前台时,我从我的 shared_prefences 中检查活动计时器,计算保存的定时器与DateTime.now()之间的差值,并从调整后的偏移量恢复定时器。

zpjtge22

zpjtge225#

面对同样的问题,找到了解决办法。我用的是钩子,但我希望你能理解原理
父类:

useEffect(() {
   if (state == AppLifecycleState.resumed) {
     lostTimeNotifier.value = handleExpireDate(context);
   }
   return null;
 });

然后我们倾听它:

return HookBuilder(builder: (context) {
   final lostTime = useValueListenable(lostTimeNotifier);
   return CountDownExpireCartWidget(
             lostSeconds: lostTime,
           );

现在来看一下子部件:

class CountDownExpireCartWidget extends Hook {...

@override
 Widget build(BuildContext context) {
 timer? timer;

 final isFinished = useValueNotifier(false);
 final timeNotifier = useValueNotifier(lostSeconds);

 void startTimer() {
   const oneSec = Duration(seconds: 1);
   timer = Timer.periodic(
     onesec,
     (timer) {
       if (timeNotifier.value < 1) {
         callBack.call();
         isFinished.value = true;
         timer.cancel();
       } else {
         timeNotifier.value--;
       }
     },
   );
 }

每次更新lostTimeNotifier的值时,都会在此方法中调用它,这是键,内部通知程序将已更新并给予当前值

useEffect(() {
   timeNotifier.value = lostSeconds;
   if (!isFinished.value) {
     startTimer();
     return() {
       timer?.cancel();
     };
   }
   return null;
 });

现在我们正在收听儿童通告:

HookBuilder(builder: (_) {
   final timer = useValueListenable(timeNotifier);

   return Text('Lost seconds: $timer');

希望对某人有帮助)

相关问题