Skip to content

Instantly share code, notes, and snippets.

@marvin-kolja
Last active October 4, 2023 08:43
Show Gist options
  • Save marvin-kolja/6181915ee0bc0992db83c06aa23f350c to your computer and use it in GitHub Desktop.
Save marvin-kolja/6181915ee0bc0992db83c06aa23f350c to your computer and use it in GitHub Desktop.
Custom Dart Periodic - with duration multiplier, run limit, and immediate callback execution
import 'dart:async';
typedef PeriodicCallback = Future<Duration?> Function(
Periodic periodic,
);
/// The [Periodic] class is a wrapper around the [Timer] class that allows you
/// to run a timer periodically with a variable duration. It allows for a bit
/// more control over a periodic run.
///
/// The [PeriodicCallback] callback returns the [Periodic] instance which lets
/// you access the current periodic state. This allows you to control when the
/// timer should be cancelled based on e.g. the current run count.
/// You can cancel the timer within the callback by calling [Periodic.cancel]
/// or change the duration for the next run by returning a new [Duration].
/// If you return `null`, the duration of the previous run will be used.
///
/// Tip: To run the timer immediately, you can pass a duration of `Duration.zero`
/// and change the duration in the [PeriodicCallback] callback for subsequent
/// runs:
///
/// ```dart
/// Periodic.run(
/// Duration.zero,
/// (periodic) async {
/// // Do something
/// return Duration(seconds: 1);
/// },
/// );
/// ```
class Periodic {
Timer? _timer;
bool _cancelled = false;
int _runCount = 0;
Duration _duration = Duration.zero;
bool get isActive => !_cancelled;
int get runCount => _runCount;
Duration get duration => _duration;
void cancel() {
_cancelled = true;
_timer?.cancel();
}
Periodic._internal({
required Duration duration,
}) : _duration = duration;
factory Periodic.run(Duration duration, PeriodicCallback callback) {
return Periodic._internal(
duration: duration,
).._run(callback);
}
void _run(PeriodicCallback callback) {
if (_cancelled) return;
_runCount++;
_timer = Timer(_duration, () async {
_duration = await callback(this) ?? _duration;
_run(callback);
});
}
}
@marvin-kolja
Copy link
Author

Replaced old periodic with the revised version. It provides more flexibility and control over the periodic task's execution but keeps the interface clean. For instance, instead of passing maxRuns, you can now check the run count in the callback and cancel as you see fit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment