Flutter stopwatch background running - flutter

I am trying to make a simple stopwatch application and I have so far implemented a stopwatch that is working while the app is running, but I want the stopwatch to continue to work while the application is closed and then resume while I open the app again. A similar app that I can compare to is RunKeeper which tracks the time of your running activities.
Is there any simple plugins that I can use to resolve my issue or is it more complicated than that?
So far I have tried using workmanager(flutter plugin) but with workmanager I could only track background activities at a given time, not the entire time the stopwatch is active, which I want in my case.

I created a stopwatch by using a Stream that returns the time with the help of Timer.periodic(). If you quit to home screen of the phone the Stream keeps running in the background.
Stream<int> stopWatchStream() {
StreamController<int> streamController;
Timer timer;
int counter = 0;
void stopTimer() {
if (timer != null) {
timer.cancel();
timer = null;
counter = 0;
streamController.close();
}
}
void tick(_) {
counter++;
streamController.add(counter);
}
void startTimer() {
timer = Timer.periodic(Duration(milliseconds: 10), tick);
}
streamController = StreamController<int>(
onListen: startTimer,
onCancel: stopTimer,
onResume: startTimer,
onPause: stopTimer,
);
return streamController.stream;
}

Related

Flutter audio_service does not start when the app is not in the foreground on iOS

I've been building a Flutter app that needs to trigger an alarm while in the background.
I am using audio_service in combination with just_audio (latest versions of both) but am only hearing the alarm if it is triggered when the app is in the foreground.
My handler always recieves the callback to start playing, and no exceptions are thrown by the audio player.
I've tried using the IsolatedAudioHandler class as explained in the FAQ and it behaves exactly the same way: sound is only heard when in the foreground.
The alarm is triggered by GPS location updates when the user leaves a guard-zone.
Any advice would be greatly appreciated.
This is my handler code:
class AudioPlayerHandler extends BaseAudioHandler {
final _player = AudioPlayer();
AudioPlayerHandler() {
_player.setUrl("https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3");
}
#override
Future<void> play() {
try {
print("****** play *******");
return _player.play();
} catch (e) {
print(e);
return Future.value(null);
}
}
#override
Future<void> pause() {
return _player.pause();
}
}```

Timer does not stop

Problem
I'm doing a chat. I want the program to try to get messages again every 5 seconds if there are no messages.
My solution
I'have created a Timer in my stateful widget.
Timer timer;
When I build a widget, I check for messages. If there are none, I start the timer. I want the timer to stop at the next check, in case of existing messages
void onBuild() {
if (state.messages.isEmpty) {
_checkEmptyMessages();
timer = Timer.periodic(
Duration(seconds: 5), (Timer t) => _checkEmptyMessages());
}
}
void _checkEmptyMessages() {
print('MES789 ${state.messages.isEmpty}');
if (state.messages.isEmpty) {
add(ChatEventLoadFirstPage()); // This adds an event to the BLoC
} else {
if (timer != null) timer.cancel();
timer = null;
}
}
Also I've tried
I've tried to remove timer = null; and await for timer.cancel();, but it didn't help.
Actual output
So in the Debug Console I get this every 5 seconds:
I/flutter (13387): MES789 false
I/flutter (13387): MES789 false
I/flutter (13387): MES789 false
I/flutter (13387): MES789 false
Question
How can I stop the Timer?
Because 'Timer.periodic' is called, new Timer instance is created and stored same timer variable.
It means that not canceled timer's instance will be lost when 'Timer.periodic' is called.
So you need to check whether Timer instance is exist.
void onBuild() {
if (state.messages.isEmpty) {
if (timer == null) {
timer = Timer.periodic(
Duration(seconds: 5), (Timer t) => add(ChatEventLoadFirstPage()));
}
} else {
if (timer != null) timer.cancel();
timer = null;
}
}
this code is dead code, it will never work because you have if (state.messages.isEmpty) before _checkEmptyMessages() and if (state.messages.isEmpty) again, try to remove first if (state.messages.isEmpty)

setState() or markNeedsBuild() called during build. Trying to make a simple timer in flutter

I am trying to make a simple timer which run till a given time. This is how I have tried to call the timer function. It gives the error as mentioned in the title. I believe the error is there because I am calling set state method in the init state, but I really need to make this functionality that, when this widget enters the screen, a timer begins and do something when the timer ends. Any help is greatly appreciated.
late double timeRemaining;
late Timer _timer;
void startTimer(double timeRemaing) {}
#override
void initState() {
timeRemaining =
widget.startDate.difference(widget.endDate).inSeconds / 1000 - 80;
const Duration seconds = Duration(seconds: 1);
_timer = Timer.periodic(seconds, (timer) {
setState(() {
timeRemaining--;
if (timeRemaining <= 0) {
// done = true;
done = true;
timer.cancel();
}
});
});
super.initState();
}
as the title says, you're building widget during another build (when you call setState in the timer).So the solution is to wait for the widget to finish building, then start your timer, this can be done by using addPostFrameCallback, like the following:
#override
void initState() {
timeRemaining =
widget.startDate.difference(widget.endDate).inSeconds / 1000 - 80;
const Duration seconds = Duration(seconds: 1);
// this will schedule a callback for the end of this frame.
WidgetsBinding.instance.addPostFrameCallback((_) {
_timer = Timer.periodic(seconds, (timer) {
setState(() {
timeRemaining--;
if (timeRemaining <= 0) {
// done = true;
done = true;
timer.cancel();
}
});
});
});
super.initState();
}
try it and tell me if this works

Flutteronic method of scheduling code to run on the next event loop

This is common in other languages. setTimeout(fn, 0) in JavaScript, and DispatchQueue.main.async() {} in Swift.
How best to do this in Flutter?
I have used Future.delayed(Duration.zero).then(fn), but I don't like it because like JS's setTimeout and unlike swifts DispatchQueue.main.async() {} it doesn't really express the intent, only the behaviour. Is there a way of doing this that is the correct way to do this in Flutter.
Use addPostFrameCallback
WidgetsBinding.instance
.addPostFrameCallback((timestamp) {
print("I'm running after the frame was built");
});
This will cause your callback function to run right after flutter has finished building the current frame.
Note that the callback will only run once, if you want to reschedule it for each build, set the callback at the beginning of the build function.
#override
Widget build(BuildContext context) {
WidgetsBinding.instance
.addPostFrameCallback((timestamp) {
print("I'm running after the frame was built");
});
return Container();
}
You can also use Timer from flutter.
Example
Timer(Duration(seconds: 1), () {
print('hai');
});
Duration gives you options with seconds,milliseconds,days,hours,minutes.
You can achieve setInterval also using Timer
Timer.periodic(Duration(seconds: 1), (Timer timer) {
print('hai');
});
But keep in mind that to cancel the timer on dispose.This would save you from hitting memory
Timer timer;
timer = Timer(Duration(seconds: 1), () {
print('hai');
});
void dispose() {
timer.cancel();
}

How do i pause and resume quiver.async CountdownTimer in flutter

i am trying to implement Countdown Timer in flutter. I got it working but cannot implement Pause and Resume feature of the class. Below is what i have tried:
import 'package:flutter/material.dart';
import 'package:quiver/async.dart';
void startTimer() {
CountdownTimer countDownTimer = new CountdownTimer(
new Duration(seconds: _start),
new Duration(seconds: 2),
);
var sub = countDownTimer.listen(null);
sub.onData((duration) {
// Here i tried try to check a bool variable and pause the timer
if(pauseTimer == true){
sub.pause();
}
// Here i tried try to check a bool variable and resume the timer
else if(pauseTimer == false){
sub.resume();
}
setState(() {
_current = _start - duration.elapsed.inSeconds;
});
if(_current == 0){
//Do something here..
}
});
sub.onDone(() {
print("Done");
sub.cancel();
});
}
The problem however is that only Pause is working, while the Resume is not working. Please any idea how to get both Pause and Resume working from button click.
Thanks
sub.resume() is not working because after pausing the timer onData does not trigger. You can simply make a single FlatButton and implement onTap just like this.
StreamSubscription sub; // declare it as a class variable and then assign it in function
bool isPaused =false; /// your state class variable
onTap :(){
if(isPaused)
sub?.resume(); // performing a null check operation here...
else
sub?.pause(); // ...if sub is null then it won't call any functions
}
//// Note:- make sure to cancel sub like
sub?.cancel();