I am trying to create a timer app that has multiple countdown timers for different tasks. The issue, I am facing is that, if I start a one-timer, and press the back button, the timer stops. So I want, that timer to run till either it is being paused or the timer ends and alerts the user or the app is destroyed. Help me how can I do this using Flutter?
Any Sample Code Will be Appreciated?
CountDownController _controller = CountDownController();
CircularCountDownTimer(
width: MediaQuery.of(context).size.width / 6,
height: MediaQuery.of(context).size.width / 6,
duration: 120,
fillColor: Colors.green,
ringColor: Colors.white,
controller: _controller,
backgroundColor: Colors.white54,
strokeWidth: 10.0,
strokeCap: StrokeCap.round,
isTimerTextShown: true,
isReverse: false,
onComplete: () {
Notify();
},
textStyle: TextStyle(fontSize: 20.0, color:
Colors.black),
),
When you pop back, any "state" in the widget will be destroyed.
There are three kinds of method you can do to prevent "state" being destroyed (or memory release):
There are still many method to manage your state, but not mention here, see details in this repo
Static property is something like variable outside your class, like:
// prefix "_" for private variable
const _myStaticVar = 'hello world';
class MyWidget {}
Rather, it is class based variable. Which means it can help you describe the variable more. like class Dog
can has a static property static final footShouldHave = 4
. Class based programing is popular because it can manage your state and any logic action "inside" the class, and make it easier to understand and code.
When the class is being destroyed (memory release), any "state" inside the class should be pop from stack but not static. You can see more detail by knowing how compiler works.
In your case, you can do something like:
class MyTimer extends StatlessWidget {
static DateTime? starter;
Widget build(context) {
if (starter == null) {
starter = DateTime.now();
}
final secondPass = (DateTime.now().millisecondsSinceEpoch - starter!.millisecondsSinceEpoch) / 1000;
final secondLeft = 60 - secondPass;
return Text(secondLeft.toString());
}
}
Provider
Provider
is made for flutter and also maintained by flutter team. It can make you easy to manage your class by accessing it from context
.
You can also set up how the class create.
lazy
, create only when you need itfuture
In your case, it should be like:
TimerManager
class TimerManager {
final DateTime? starter;
void startIfNeed() {
if (starter != null) {
starter = DateTime.now();
}
}
num get secondLeft => 60 - (DateTime.now().millisecondsSinceEpoch - starter!.millisecondsSinceEpoch) / 1000
}
Provider
class Homepage extends statelessWidget {
Widget build(context) {
return TextButton(
onPressed: () => navigateToTimer(context),
child: Text('go'),
);
}
void navigateToTimer(Build context) {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => MyTimer()),
);
}
}
void main() {
runApp(MaterialApp(
home: Provider<TimerManager>(
create: () => TimerManager(),
child: Homepage(),
)
));
}
context
.Now when your widget is released, it is still existed in parent context
(if their do exist a parent).
// remember to import provider to able `context.read()`.
// see more detail in document.
import 'package:provider/provider.dart';
class MyTimer extends StatlessWidget {
Widget build(context) {
final manager = context.read<TimerManager>();
manager.startIfNeed();
return Text(manager.secondLeft.toString());
}
}
Kind of combined method from 1 and 2.
class TimerManager {
// make it singleton
static final TimerManager instance = TimerManager._();
// It is now private constructor
const TimerManager._();
...
}
Just call it in your widget
class MyTimer extends StatlessWidget {
Widget build(context) {
TimerManager.instance.startIfNeed();
return Text(TimerManager.instance.secondLeft.toString());
}
}
There is no best way to keep your state in generally, but in your case, I recommend Provider
method.