Всем привет! Это статья для тех, кто увлекается Flutter-разработкой. А я Николай — человек, который рулит этим направлением в Mad Brains. Поговорим о Timer и Ticker?
Итак, представим, что нам нужно построить экран, в котором будет отображаться текущее Unix-время в миллисекундах. Давайте сначала сделаем верстку без анимации.

В исходном коде нет ничего необычного — пара виджетов и ValueNotifier _msSinceEpoch для Unix-времени?
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const HomePage(), ); } } class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { late final ValueNotifier<int> _msSinceEpoch; @override void initState() { super.initState(); _msSinceEpoch = ValueNotifier(DateTime.now().millisecondsSinceEpoch); } @override void dispose() { _msSinceEpoch.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: const Text('Home page'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ _TimerCard( child: ValueListenableBuilder<int>( valueListenable: _msSinceEpoch, builder: (BuildContext context, int value, ___) => Text( value.toString(), style: Theme.of(context).textTheme.headlineMedium, ), ), ), Text( 'milliseconds since epoch', style: Theme.of(context).textTheme.headlineSmall, ), ], ), ), ); } } class _TimerCard extends StatelessWidget { const _TimerCard({required this.child}); final Widget child; @override Widget build(BuildContext context) { return Card( margin: const EdgeInsets.only(bottom: 16), child: Padding( padding: const EdgeInsets.all(16), child: child, ), ); } }
Используем Timer
Теперь переходим к главному вопросу — как обновлять текущее время в _msSinceEpoch? Первое, что приходит на ум — это использовать Timer.periodic. В нем мы будем вызывать callback на обновление значения.

Я залочил обновление таймера на 16 мс ради обновления виджета 60 раз в секунду. Всё хорошо работает, даже видно изменение времени, но у этого решения есть свои минусы.

Чем плох Timer?
⛔️ Нет удобного решения для работы в 60/120 FPS в зависимости от частоты экрана телефона
⛔️ Зависимость от времени, а не от построения кадра
⛔️ При скрытии виджета с экрана таймер продолжить работать и вызывать callback
Используем Ticker
К счастью, Flutter содержит встроенное решение, которое одновременно и покрывает возможности таймера, и лишено его минусов.
Встречайте, Ticker! Я думаю, вам уже не раз приходилось работать с ним, но не напрямую, а через AnimationController, который создаёт Ticker внутри себя.
Чтобы работать с Ticker’ом, нужно добавить миксин SingleTickerProviderStateMixin (или TickerProviderStateMixin) к стейту виджета. Так у нас появляется доступ к методу createTicker внутри этого стейта.
Взаимодействовать с ним также просто, как и с таймером.
Как работает Ticker
-
Ticker требует SchedulerBinding зарегистрировать callback
-
SchedulerBinding сообщает Flutter Engine, что надо разбудить Ticker, когда появится новый callback
-
Когда Flutter Engine готов, он вызывает SchedulerBinding через запрос onBeginFrame
-
SchedulerBinding обращается к списку обратных вызовов запланированный Ticker’ами и выполняет каждый из них
-
Если анимация завершена, то Ticker отключается, иначе Ticker запрашивает SchedulerBinding для планирования нового callback

Чем хорош Ticker?
-
Автоматически вызывает callback в зависимости от частоты экрана телефона
-
Зависит от вызова построения кадра SchedulerBinding.onBeginFrame
-
Не вызывает callback, если стейт не в дереве
Вывод
Старайтесь по возможности сократить использование Timer для анимаций. И почаще используйте Ticker.
ссылка на оригинал статьи https://habr.com/ru/articles/819863/
Добавить комментарий