SchedulerBinding源码解析

arduino 复制代码
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// 中文:版权所有 2014 The Flutter Authors。保留所有权利。
// 中文:本代码的使用受 BSD 许可证的约束,该许可证可在
// 中文:LICENSE 文件中找到。

/// @docImport 'package:flutter/material.dart';
/// @docImport 'package:flutter/rendering.dart';
/// @docImport 'package:flutter/services.dart';
/// @docImport 'package:flutter/widgets.dart';
///
/// @docImport 'ticker.dart';
library;

import 'dart:async';
import 'dart:collection';
import 'dart:developer' show Flow, Timeline, TimelineTask;
import 'dart:ui' show AppLifecycleState, DartPerformanceMode, FramePhase, FrameTiming, PlatformDispatcher, TimingsCallback;

import 'package:collection/collection.dart' show HeapPriorityQueue, PriorityQueue;
import 'package:flutter/foundation.dart';

import 'debug.dart';
import 'priority.dart';
import 'service_extensions.dart';

export 'dart:ui' show AppLifecycleState, FrameTiming, TimingsCallback;

export 'priority.dart' show Priority;

/// Slows down animations by this factor to help in development.
/// 中文:通过此因子减慢动画速度,以帮助开发。
double get timeDilation => _timeDilation;
double _timeDilation = 1.0;
/// If the [SchedulerBinding] has been initialized, setting the time dilation
/// automatically calls [SchedulerBinding.resetEpoch] to ensure that time stamps
/// seen by consumers of the scheduler binding are always increasing.
///
/// It is safe to set this before initializing the binding.
/// 中文:如果 [SchedulerBinding] 已经初始化,设置时间膨胀
/// 中文:会自动调用 [SchedulerBinding.resetEpoch] 以确保调度器绑定的消费者
/// 中文:看到的时间戳总是递增的。
///
/// 中文:在初始化绑定之前设置这个值是安全的。
set timeDilation(double value) {
  assert(value > 0.0);
  if (_timeDilation == value) {
    return;
  }
  // If the binding has been created, we need to resetEpoch first so that we
  // capture start of the epoch with the current time dilation.
  // 中文:如果绑定已经创建,我们需要先调用resetEpoch,以便
  // 中文:使用当前的时间膨胀捕获时代的开始。
  SchedulerBinding._instance?.resetEpoch();
  _timeDilation = value;
}

/// Signature for frame-related callbacks from the scheduler.
///
/// The `timeStamp` is the number of milliseconds since the beginning of the
/// scheduler's epoch. Use timeStamp to determine how far to advance animation
/// timelines so that all the animations in the system are synchronized to a
/// common time base.
/// 中文:调度器的帧相关回调的签名。
///
/// 中文:`timeStamp` 是自调度器纪元开始以来的毫秒数。使用timeStamp来确定
/// 中文:动画时间线应该前进多少,以便系统中的所有动画都同步到
/// 中文:一个共同的时间基准。
typedef FrameCallback = void Function(Duration timeStamp);
java 复制代码
/// Signature for [SchedulerBinding.scheduleTask] callbacks.
///
/// The type argument `T` is the task's return value. Consider `void` if the
/// task does not return a value.
/// 中文:[SchedulerBinding.scheduleTask] 回调的签名。
///
/// 中文:类型参数 `T` 是任务的返回值。如果任务不返回值,可以考虑使用 `void`。
typedef TaskCallback<T> = FutureOr<T> Function();

/// Signature for the [SchedulerBinding.schedulingStrategy] callback. Called
/// whenever the system needs to decide whether a task at a given
/// priority needs to be run.
///
/// Return true if a task with the given priority should be executed at this
/// time, false otherwise.
///
/// See also:
///
///  * [defaultSchedulingStrategy], the default [SchedulingStrategy] for [SchedulerBinding.schedulingStrategy].
/// 中文:[SchedulerBinding.schedulingStrategy] 回调的签名。每当系统需要
/// 中文:决定是否应该执行给定优先级的任务时调用。
///
/// 中文:如果应该在此时执行具有给定优先级的任务,则返回true,否则返回false。
///
/// 中文:另请参阅:
///
/// 中文: * [defaultSchedulingStrategy],[SchedulerBinding.schedulingStrategy]的默认[SchedulingStrategy]。
typedef SchedulingStrategy = bool Function({ required int priority, required SchedulerBinding scheduler });

class _TaskEntry<T> {
  _TaskEntry(this.task, this.priority, this.debugLabel, this.flow) {
    assert(() {
      debugStack = StackTrace.current;
      return true;
    }());
  }
  final TaskCallback<T> task;
  final int priority;
  final String? debugLabel;
  final Flow? flow;

  late StackTrace debugStack;
  final Completer<T> completer = Completer<T>();

  void run() {
    if (!kReleaseMode) {
      Timeline.timeSync(
        debugLabel ?? 'Scheduled Task',
        () {
          completer.complete(task());
        },
        flow: flow != null ? Flow.step(flow!.id) : null,
      );
    } else {
      completer.complete(task());
    }
  }
}

class _FrameCallbackEntry {
  _FrameCallbackEntry(this.callback, { bool rescheduling = false }) {
    assert(() {
      if (rescheduling) {
        assert(() {
          if (debugCurrentCallbackStack == null) {
            throw FlutterError.fromParts(<DiagnosticsNode>[
              ErrorSummary('scheduleFrameCallback called with rescheduling true, but no callback is in scope.'),
              // 中文:scheduleFrameCallback被调用时rescheduling为true,但没有回调在作用域内。
              ErrorDescription(
                'The "rescheduling" argument should only be set to true if the '
                'callback is being reregistered from within the callback itself, '
                'and only then if the callback itself is entirely synchronous.',
                // 中文:"rescheduling"参数应该只在回调本身被重新注册时设置为true,
                // 中文:并且只有在回调本身完全是同步的情况下。
              ),
              ErrorHint(
                'If this is the initial registration of the callback, or if the '
                'callback is asynchronous, then do not use the "rescheduling" '
                'argument.',
                // 中文:如果这是回调的初始注册,或者回调是异步的,
                // 中文:那么不要使用"rescheduling"参数。
              ),
            ]);
          }
          return true;
        }());
        debugStack = debugCurrentCallbackStack;
      } else {
        // TODO(ianh): trim the frames from this library, so that the call to scheduleFrameCallback is the top one
        // 中文:TODO(ianh): 从这个库中修剪帧,使对scheduleFrameCallback的调用成为顶部的帧
        debugStack = StackTrace.current;
      }
      return true;
    }());
  }

  final FrameCallback callback;

  static StackTrace? debugCurrentCallbackStack;
  StackTrace? debugStack;
}

/// The various phases that a [SchedulerBinding] goes through during
/// [SchedulerBinding.handleBeginFrame].
///
/// This is exposed by [SchedulerBinding.schedulerPhase].
///
/// The values of this enum are ordered in the same order as the phases occur,
/// so their relative index values can be compared to each other.
///
/// See also:
///
///  * [WidgetsBinding.drawFrame], which pumps the build and rendering pipeline
///    to generate a frame.
/// 中文:[SchedulerBinding]在[SchedulerBinding.handleBeginFrame]期间经历的各个阶段。
///
/// 中文:这由[SchedulerBinding.schedulerPhase]暴露。
///
/// 中文:此枚举的值按照阶段发生的顺序排序,
/// 中文:因此它们的相对索引值可以相互比较。
///
/// 中文:另请参阅:
///
/// 中文: * [WidgetsBinding.drawFrame],它泵送构建和渲染管道
/// 中文:   以生成一帧。
enum SchedulerPhase {
  /// No frame is being processed. Tasks (scheduled by
  /// [SchedulerBinding.scheduleTask]), microtasks (scheduled by
  /// [scheduleMicrotask]), [Timer] callbacks, event handlers (e.g. from user
  /// input), and other callbacks (e.g. from [Future]s, [Stream]s, and the like)
  /// may be executing.
  /// 中文:没有帧正在处理。任务(由[SchedulerBinding.scheduleTask]调度),
  /// 中文:微任务(由[scheduleMicrotask]调度),[Timer]回调,事件处理程序
  /// 中文:(例如来自用户输入),以及其他回调(例如来自[Future],[Stream]等)
  /// 中文:可能正在执行。
  idle,

  /// The transient callbacks (scheduled by
  /// [SchedulerBinding.scheduleFrameCallback]) are currently executing.
  ///
  /// Typically, these callbacks handle updating objects to new animation
  /// states.
  ///
  /// See [SchedulerBinding.handleBeginFrame].
  /// 中文:瞬态回调(由[SchedulerBinding.scheduleFrameCallback]调度)
  /// 中文:当前正在执行。
  ///
  /// 中文:通常,这些回调处理将对象更新到新的动画状态。
  ///
  /// 中文:参见[SchedulerBinding.handleBeginFrame]。
  transientCallbacks,

  /// Microtasks scheduled during the processing of transient callbacks are
  /// current executing.
  ///
  /// This may include, for instance, callbacks from futures resolved during the
  /// [transientCallbacks] phase.
  /// 中文:在处理瞬态回调期间调度的微任务当前正在执行。
  ///
  /// 中文:这可能包括,例如,在[transientCallbacks]阶段解析的future的回调。
  midFrameMicrotasks,

  /// The persistent callbacks (scheduled by
  /// [SchedulerBinding.addPersistentFrameCallback]) are currently executing.
  ///
  /// Typically, this is the build/layout/paint pipeline. See
  /// [WidgetsBinding.drawFrame] and [SchedulerBinding.handleDrawFrame].
  /// 中文:持久回调(由[SchedulerBinding.addPersistentFrameCallback]调度)
  /// 中文:当前正在执行。
  ///
  /// 中文:通常,这是构建/布局/绘制管道。参见
  /// 中文:[WidgetsBinding.drawFrame]和[SchedulerBinding.handleDrawFrame]。
  persistentCallbacks,

  /// The post-frame callbacks (scheduled by
  /// [SchedulerBinding.addPostFrameCallback]) are currently executing.
  ///
  /// Typically, these callbacks handle cleanup and scheduling of work for the
  /// next frame.
  ///
  /// See [SchedulerBinding.handleDrawFrame].
  /// 中文:帧后回调(由[SchedulerBinding.addPostFrameCallback]调度)
  /// 中文:当前正在执行。
  ///
  /// 中文:通常,这些回调处理清理和为下一帧调度工作。
  ///
  /// 中文:参见[SchedulerBinding.handleDrawFrame]。
  postFrameCallbacks,
}
kotlin 复制代码
/// This callback is invoked when a request for [DartPerformanceMode] is disposed.
///
/// See also:
///
/// * [PerformanceModeRequestHandle] for more information on the lifecycle of the handle.
/// 中文:当[DartPerformanceMode]请求被处置时调用此回调。
///
/// 中文:另请参阅:
///
/// 中文:* [PerformanceModeRequestHandle] 有关句柄生命周期的更多信息。
typedef _PerformanceModeCleanupCallback = VoidCallback;

/// An opaque handle that keeps a request for [DartPerformanceMode] active until
/// disposed.
///
/// To create a [PerformanceModeRequestHandle], use [SchedulerBinding.requestPerformanceMode].
/// The component that makes the request is responsible for disposing the handle.
/// 中文:一个不透明的句柄,它保持对[DartPerformanceMode]的请求处于活动状态,直到
/// 中文:被处置。
///
/// 中文:要创建[PerformanceModeRequestHandle],请使用[SchedulerBinding.requestPerformanceMode]。
/// 中文:发出请求的组件负责处置句柄。
class PerformanceModeRequestHandle {
  PerformanceModeRequestHandle._(_PerformanceModeCleanupCallback this._cleanup) {
    // TODO(polina-c): stop duplicating code across disposables
    // [https://github.com/flutter/flutter/issues/137435](https://github.com/flutter/flutter/issues/137435)
    // 中文:TODO(polina-c): 停止在可处置对象间复制代码
    // 中文:[https://github.com/flutter/flutter/issues/137435](https://github.com/flutter/flutter/issues/137435)
    if (kFlutterMemoryAllocationsEnabled) {
      FlutterMemoryAllocations.instance.dispatchObjectCreated(
        library: 'package:flutter/scheduler.dart',
        className: '$PerformanceModeRequestHandle',
        object: this,
      );
    }
  }

  _PerformanceModeCleanupCallback? _cleanup;

  /// Call this method to signal to [SchedulerBinding] that a request for a [DartPerformanceMode]
  /// is no longer needed.
  ///
  /// This method must only be called once per object.
  /// 中文:调用此方法向[SchedulerBinding]表明对[DartPerformanceMode]的请求
  /// 中文:不再需要。
  ///
  /// 中文:此方法每个对象只能调用一次。
  void dispose() {
    assert(_cleanup != null);
    // TODO(polina-c): stop duplicating code across disposables
    // [https://github.com/flutter/flutter/issues/137435](https://github.com/flutter/flutter/issues/137435)
    // 中文:TODO(polina-c): 停止在可处置对象间复制代码
    // 中文:[https://github.com/flutter/flutter/issues/137435](https://github.com/flutter/flutter/issues/137435)
    if (kFlutterMemoryAllocationsEnabled) {
      FlutterMemoryAllocations.instance.dispatchObjectDisposed(object: this);
    }
    _cleanup!();
    _cleanup = null;
  }
}
scss 复制代码
/// Scheduler for running the following:
///
/// * _Transient callbacks_, triggered by the system's
///   [dart:ui.PlatformDispatcher.onBeginFrame] callback, for synchronizing the
///   application's behavior to the system's display. For example, [Ticker]s and
///   [AnimationController]s trigger from these.
///
/// * _Persistent callbacks_, triggered by the system's
///   [dart:ui.PlatformDispatcher.onDrawFrame] callback, for updating the
///   system's display after transient callbacks have executed. For example, the
///   rendering layer uses this to drive its rendering pipeline.
///
/// * _Post-frame callbacks_, which are run after persistent callbacks, just
///   before returning from the [dart:ui.PlatformDispatcher.onDrawFrame] callback.
///
/// * Non-rendering tasks, to be run between frames. These are given a
///   priority and are executed in priority order according to a
///   [schedulingStrategy].
/// 中文:用于运行以下内容的调度器:
///
/// 中文:* _瞬态回调_,由系统的[dart:ui.PlatformDispatcher.onBeginFrame]回调触发,
/// 中文:  用于将应用程序的行为与系统的显示同步。例如,[Ticker]和
/// 中文:  [AnimationController]从这些触发。
///
/// 中文:* _持久回调_,由系统的[dart:ui.PlatformDispatcher.onDrawFrame]回调触发,
/// 中文:  用于在瞬态回调执行后更新系统的显示。例如,渲染层使用
/// 中文:  这个来驱动其渲染管道。
///
/// 中文:* _帧后回调_,在持久回调之后运行,就在从
/// 中文:  [dart:ui.PlatformDispatcher.onDrawFrame]回调返回之前。
///
/// 中文:* 非渲染任务,在帧之间运行。这些被赋予优先级,并按照
/// 中文:  [schedulingStrategy]确定的优先级顺序执行。
mixin SchedulerBinding on BindingBase {
  @override
  void initInstances() {
    super.initInstances();
    _instance = this;

    if (!kReleaseMode) {
      addTimingsCallback((List<FrameTiming> timings) {
        timings.forEach(_profileFramePostEvent);
      });
    }
  }

  /// The current [SchedulerBinding], if one has been created.
  ///
  /// Provides access to the features exposed by this mixin. The binding must
  /// be initialized before using this getter; this is typically done by calling
  /// [runApp] or [WidgetsFlutterBinding.ensureInitialized].
  /// 中文:当前的[SchedulerBinding],如果已创建。
  ///
  /// 中文:提供对此mixin暴露的功能的访问。绑定必须在使用此getter之前
  /// 中文:初始化;这通常通过调用[runApp]或[WidgetsFlutterBinding.ensureInitialized]完成。
  static SchedulerBinding get instance => BindingBase.checkInstance(_instance);
  static SchedulerBinding? _instance;

  final List<TimingsCallback> _timingsCallbacks = <TimingsCallback>[];
java 复制代码
  /// Add a [TimingsCallback] that receives [FrameTiming] sent from
  /// the engine.
  ///
  /// This API enables applications to monitor their graphics
  /// performance. Data from the engine is batched into lists of
  /// [FrameTiming] objects which are reported approximately once a
  /// second in release mode and approximately once every 100ms in
  /// debug and profile builds. The list is sorted in ascending
  /// chronological order (earliest frame first). The timing of the
  /// first frame is sent immediately without batching.
  ///
  /// The data returned can be used to catch missed frames (by seeing
  /// if [FrameTiming.buildDuration] or [FrameTiming.rasterDuration]
  /// exceed the frame budget, e.g. 16ms at 60Hz), and to catch high
  /// latency (by seeing if [FrameTiming.totalSpan] exceeds the frame
  /// budget). It is possible for no frames to be missed but for the
  /// latency to be more than one frame in the case where the Flutter
  /// engine is pipelining the graphics updates, e.g. because the sum
  /// of the [FrameTiming.buildDuration] and the
  /// [FrameTiming.rasterDuration] together exceed the frame budget.
  /// In those cases, animations will be smooth but touch input will
  /// feel more sluggish.
  ///
  /// Using [addTimingsCallback] is preferred over using
  /// [dart:ui.PlatformDispatcher.onReportTimings] directly because the
  /// [dart:ui.PlatformDispatcher.onReportTimings] API only allows one callback,
  /// which prevents multiple libraries from registering listeners
  /// simultaneously, while this API allows multiple callbacks to be registered
  /// independently.
  ///
  /// This API is implemented in terms of
  /// [dart:ui.PlatformDispatcher.onReportTimings]. In release builds, when no
  /// libraries have registered with this API, the
  /// [dart:ui.PlatformDispatcher.onReportTimings] callback is not set, which
  /// disables the performance tracking and reduces the runtime overhead to
  /// approximately zero. The performance overhead of the performance tracking
  /// when one or more callbacks are registered (i.e. when it is enabled) is
  /// very approximately 0.01% CPU usage per second (measured on an iPhone 6s).
  ///
  /// In debug and profile builds, the [SchedulerBinding] itself
  /// registers a timings callback to update the [Timeline].
  ///
  /// If the same callback is added twice, it will be executed twice.
  ///
  /// See also:
  ///
  ///  * [removeTimingsCallback], which can be used to remove a callback
  ///    added using this method.
  /// 中文:添加一个[TimingsCallback],接收从引擎发送的[FrameTiming]。
  ///
  /// 中文:此API使应用程序能够监控其图形性能。来自引擎的数据被批处理成
  /// 中文:[FrameTiming]对象列表,在发布模式下大约每秒报告一次,
  /// 中文:在调试和配置文件构建中大约每100毫秒报告一次。列表按升序
  /// 中文:时间顺序排序(最早的帧在前)。第一帧的计时立即发送,
  /// 中文:不进行批处理。
  ///
  /// 中文:返回的数据可用于捕获丢失的帧(通过查看
  /// 中文:[FrameTiming.buildDuration]或[FrameTiming.rasterDuration]
  /// 中文:是否超过帧预算,例如60Hz时为16毫秒),以及捕获高
  /// 中文:延迟(通过查看[FrameTiming.totalSpan]是否超过帧
  /// 中文:预算)。在没有丢失帧但延迟超过一帧的情况下,
  /// 中文:Flutter引擎正在流水线处理图形更新,例如因为
  /// 中文:[FrameTiming.buildDuration]和[FrameTiming.rasterDuration]
  /// 中文:的总和超过了帧预算。在这些情况下,动画将是平滑的,
  /// 中文:但触摸输入会感觉更加迟缓。
  ///
  /// 中文:使用[addTimingsCallback]比直接使用
  /// 中文:[dart:ui.PlatformDispatcher.onReportTimings]更好,因为
  /// 中文:[dart:ui.PlatformDispatcher.onReportTimings] API只允许一个回调,
  /// 中文:这阻止了多个库同时注册监听器,而此API允许
  /// 中文:独立注册多个回调。
  ///
  /// 中文:此API是基于[dart:ui.PlatformDispatcher.onReportTimings]实现的。
  /// 中文:在发布构建中,当没有库通过此API注册时,
  /// 中文:[dart:ui.PlatformDispatcher.onReportTimings]回调不会设置,
  /// 中文:这会禁用性能跟踪并将运行时开销降低到
  /// 中文:接近零。当注册了一个或多个回调(即启用时)的性能跟踪的
  /// 中文:性能开销非常小,大约为每秒0.01%的CPU使用率(在iPhone 6s上测量)。
  ///
  /// 中文:在调试和配置文件构建中,[SchedulerBinding]本身
  /// 中文:注册一个计时回调来更新[Timeline]。
  ///
  /// 中文:如果同一回调被添加两次,它将被执行两次。
  ///
  /// 中文:另请参阅:
  ///
  /// 中文: * [removeTimingsCallback],可用于删除使用此方法
  /// 中文:   添加的回调。
  void addTimingsCallback(TimingsCallback callback) {
    _timingsCallbacks.add(callback);
    if (_timingsCallbacks.length == 1) {
      assert(platformDispatcher.onReportTimings == null);
      platformDispatcher.onReportTimings = _executeTimingsCallbacks;
    }
    assert(platformDispatcher.onReportTimings == _executeTimingsCallbacks);
  }

  /// Removes a callback that was earlier added by [addTimingsCallback].
  /// 中文:删除先前由[addTimingsCallback]添加的回调。
  void removeTimingsCallback(TimingsCallback callback) {
    assert(_timingsCallbacks.contains(callback));
    _timingsCallbacks.remove(callback);
    if (_timingsCallbacks.isEmpty) {
      platformDispatcher.onReportTimings = null;
    }
  }

  @pragma('vm:notify-debugger-on-exception')
  void _executeTimingsCallbacks(List<FrameTiming> timings) {
    final List<TimingsCallback> clonedCallbacks =
        List<TimingsCallback>.of(_timingsCallbacks);
    for (final TimingsCallback callback in clonedCallbacks) {
      try {
        if (_timingsCallbacks.contains(callback)) {
          callback(timings);
        }
      } catch (exception, stack) {
        InformationCollector? collector;
        assert(() {
          collector = () => <DiagnosticsNode>[
            DiagnosticsProperty<TimingsCallback>(
              'The TimingsCallback that gets executed was',
              // 中文:执行的TimingsCallback是
              callback,
              style: DiagnosticsTreeStyle.errorProperty,
            ),
          ];
          return true;
        }());
        FlutterError.reportError(FlutterErrorDetails(
          exception: exception,
          stack: stack,
          context: ErrorDescription('while executing callbacks for FrameTiming'),
          // 中文:执行FrameTiming回调时
          informationCollector: collector,
        ));
      }
    }
  }

  @override
  void initServiceExtensions() {
    super.initServiceExtensions();

    if (!kReleaseMode) {
      registerNumericServiceExtension(
        name: SchedulerServiceExtensions.timeDilation.name,
        getter: () async => timeDilation,
        setter: (double value) async {
          timeDilation = value;
        },
      );
    }
  }

  /// Whether the application is visible, and if so, whether it is currently
  /// interactive.
  ///
  /// This is set by [handleAppLifecycleStateChanged] when the
  /// [SystemChannels.lifecycle] notification is dispatched.
  ///
  /// The preferred ways to watch for changes to this value are using
  /// [WidgetsBindingObserver.didChangeAppLifecycleState], or through an
  /// [AppLifecycleListener] object.
  /// 中文:应用程序是否可见,如果可见,当前是否可交互。
  ///
  /// 中文:这由[handleAppLifecycleStateChanged]在[SystemChannels.lifecycle]
  /// 中文:通知被分派时设置。
  ///
  /// 中文:观察此值变化的首选方法是使用
  /// 中文:[WidgetsBindingObserver.didChangeAppLifecycleState],或通过
  /// 中文:[AppLifecycleListener]对象。
  AppLifecycleState? get lifecycleState => _lifecycleState;
  AppLifecycleState? _lifecycleState;

  /// Allows the test framework to reset the lifecycle state and framesEnabled
  /// back to their initial values.
  /// 中文:允许测试框架将生命周期状态和framesEnabled
  /// 中文:重置回初始值。
  @visibleForTesting
  void resetInternalState() {
    _lifecycleState = null;
    _framesEnabled = true;
  }

  /// Called when the application lifecycle state changes.
  ///
  /// Notifies all the observers using
  /// [WidgetsBindingObserver.didChangeAppLifecycleState].
  ///
  /// This method exposes notifications from [SystemChannels.lifecycle].
  /// 中文:当应用程序生命周期状态改变时调用。
  ///
  /// 中文:使用[WidgetsBindingObserver.didChangeAppLifecycleState]
  /// 中文:通知所有观察者。
  ///
  /// 中文:此方法暴露来自[SystemChannels.lifecycle]的通知。
  @protected
  @mustCallSuper
  void handleAppLifecycleStateChanged(AppLifecycleState state) {
    if (lifecycleState == state) {
      return;
    }
    _lifecycleState = state;
    switch (state) {
      case AppLifecycleState.resumed:
      case AppLifecycleState.inactive:
        _setFramesEnabledState(true);
      case AppLifecycleState.hidden:
      case AppLifecycleState.paused:
      case AppLifecycleState.detached:
        _setFramesEnabledState(false);
    }
  }

  /// The strategy to use when deciding whether to run a task or not.
  ///
  /// Defaults to [defaultSchedulingStrategy].
  /// 中文:决定是否运行任务的策略。
  ///
  /// 中文:默认为[defaultSchedulingStrategy]。
  SchedulingStrategy schedulingStrategy = defaultSchedulingStrategy;

  static int _taskSorter (_TaskEntry<dynamic> e1, _TaskEntry<dynamic> e2) {
    return -e1.priority.compareTo(e2.priority);
  }
  final PriorityQueue<_TaskEntry<dynamic>> _taskQueue = HeapPriorityQueue<_TaskEntry<dynamic>>(_taskSorter);
java 复制代码
  /// Schedules the given `task` with the given `priority`.
  ///
  /// If `task` returns a future, the future returned by [scheduleTask] will
  /// complete after the former future has been scheduled to completion.
  /// Otherwise, the returned future for [scheduleTask] will complete with the
  /// same value returned by `task` after it has been scheduled.
  ///
  /// The `debugLabel` and `flow` are used to report the task to the [Timeline],
  /// for use when profiling.
  ///
  /// ## Processing model
  ///
  /// Tasks will be executed between frames, in priority order,
  /// excluding tasks that are skipped by the current
  /// [schedulingStrategy]. Tasks should be short (as in, up to a
  /// millisecond), so as to not cause the regular frame callbacks to
  /// get delayed.
  ///
  /// If an animation is running, including, for instance, a [ProgressIndicator]
  /// indicating that there are pending tasks, then tasks with a priority below
  /// [Priority.animation] won't run (at least, not with the
  /// [defaultSchedulingStrategy]; this can be configured using
  /// [schedulingStrategy]).
  /// 中文:使用给定的`priority`调度给定的`task`。
  ///
  /// 中文:如果`task`返回future,则[scheduleTask]返回的future将
  /// 中文:在前者future被调度完成后完成。
  /// 中文:否则,[scheduleTask]返回的future将在`task`
  /// 中文:被调度后以与`task`返回的相同值完成。
  ///
  /// 中文:`debugLabel`和`flow`用于在分析时向[Timeline]报告任务。
  ///
  /// 中文:## 处理模型
  ///
  /// 中文:任务将在帧之间按优先级顺序执行,
  /// 中文:排除当前[schedulingStrategy]跳过的任务。任务应该很短
  /// 中文:(最多一毫秒),以免导致常规帧回调延迟。
  ///
  /// 中文:如果动画正在运行,包括,例如,[ProgressIndicator]
  /// 中文:指示有待处理的任务,那么优先级低于
  /// 中文:[Priority.animation]的任务不会运行(至少,不会使用
  /// 中文:[defaultSchedulingStrategy];这可以通过
  /// 中文:[schedulingStrategy]配置)。
  Future<T> scheduleTask<T>(
    TaskCallback<T> task,
    Priority priority, {
    String? debugLabel,
    Flow? flow,
  }) {
    final bool isFirstTask = _taskQueue.isEmpty;
    final _TaskEntry<T> entry = _TaskEntry<T>(
      task,
      priority.value,
      debugLabel,
      flow,
    );
    _taskQueue.add(entry);
    if (isFirstTask && !locked) {
      _ensureEventLoopCallback();
    }
    return entry.completer.future;
  }

  @override
  void unlocked() {
    super.unlocked();
    if (_taskQueue.isNotEmpty) {
      _ensureEventLoopCallback();
    }
  }

  // Whether this scheduler already requested to be called from the event loop.
  // 中文:此调度器是否已经请求从事件循环中调用。
  bool _hasRequestedAnEventLoopCallback = false;

  // Ensures that the scheduler services a task scheduled by
  // [SchedulerBinding.scheduleTask].
  // 中文:确保调度器服务由[SchedulerBinding.scheduleTask]调度的任务。
  void _ensureEventLoopCallback() {
    assert(!locked);
    assert(_taskQueue.isNotEmpty);
    if (_hasRequestedAnEventLoopCallback) {
      return;
    }
    _hasRequestedAnEventLoopCallback = true;
    Timer.run(_runTasks);
  }

  // Scheduled by _ensureEventLoopCallback.
  // 中文:由_ensureEventLoopCallback调度。
  void _runTasks() {
    _hasRequestedAnEventLoopCallback = false;
    if (handleEventLoopCallback()) {
      _ensureEventLoopCallback();
    } // runs next task when there's time
      // 中文:当有时间时运行下一个任务
  }

  /// Execute the highest-priority task, if it is of a high enough priority.
  ///
  /// Returns false if the scheduler is [locked], or if there are no tasks
  /// remaining.
  ///
  /// Returns true otherwise, including when no task is executed due to priority
  /// being too low.
  /// 中文:执行最高优先级的任务,如果它的优先级足够高。
  ///
  /// 中文:如果调度器[locked],或者没有剩余任务,则返回false。
  ///
  /// 中文:否则返回true,包括当由于优先级太低而没有执行任务的情况。
  @visibleForTesting
  @pragma('vm:notify-debugger-on-exception')
  bool handleEventLoopCallback() {
    if (_taskQueue.isEmpty || locked) {
      return false;
    }
    final _TaskEntry<dynamic> entry = _taskQueue.first;
    if (schedulingStrategy(priority: entry.priority, scheduler: this)) {
      try {
        _taskQueue.removeFirst();
        entry.run();
      } catch (exception, exceptionStack) {
        StackTrace? callbackStack;
        assert(() {
          callbackStack = entry.debugStack;
          return true;
        }());
        FlutterError.reportError(FlutterErrorDetails(
          exception: exception,
          stack: exceptionStack,
          library: 'scheduler library',
          context: ErrorDescription('during a task callback'),
          // 中文:在任务回调期间
          informationCollector: (callbackStack == null) ? null : () {
            return <DiagnosticsNode>[
              DiagnosticsStackTrace(
                '\nThis exception was thrown in the context of a scheduler callback. '
                'When the scheduler callback was _registered_ (as opposed to when the '
                'exception was thrown), this was the stack',
                // 中文:\n这个异常是在调度器回调的上下文中抛出的。
                // 中文:当调度器回调被_注册_(而不是异常被抛出)时,这是堆栈
                callbackStack,
              ),
            ];
          },
        ));
      }
      return _taskQueue.isNotEmpty;
    }
    return true;
  }
csharp 复制代码
  int _nextFrameCallbackId = 0; // positive
  Map<int, _FrameCallbackEntry> _transientCallbacks = <int, _FrameCallbackEntry>{};
  final Set<int> _removedIds = HashSet<int>();

  /// The current number of transient frame callbacks scheduled.
  ///
  /// This is reset to zero just before all the currently scheduled
  /// transient callbacks are called, at the start of a frame.
  ///
  /// This number is primarily exposed so that tests can verify that
  /// there are no unexpected transient callbacks still registered
  /// after a test's resources have been gracefully disposed.
  /// 中文:当前调度的瞬态帧回调数量。
  ///
  /// 中文:这在帧开始时,在调用所有当前调度的瞬态回调之前,
  /// 中文:重置为零。
  ///
  /// 中文:这个数字主要是暴露出来,以便测试可以验证
  /// 中文:在测试的资源被优雅地处置后没有意外的瞬态回调
  /// 中文:仍然注册。
  int get transientCallbackCount => _transientCallbacks.length;

  /// Schedules the given transient frame callback.
  ///
  /// Adds the given callback to the list of frame callbacks and ensures that a
  /// frame is scheduled.
  ///
  /// If this is called during the frame's animation phase (when transient frame
  /// callbacks are still being invoked), a new frame will be scheduled, and
  /// `callback` will be called in the newly scheduled frame, not in the current
  /// frame.
  ///
  /// If this is a one-off registration, ignore the `rescheduling` argument.
  ///
  /// If this is a callback that will be re-registered each time it fires, then
  /// when you re-register the callback, set the `rescheduling` argument to
  /// true. This has no effect in release builds, but in debug builds, it
  /// ensures that the stack trace that is stored for this callback is the
  /// original stack trace for when the callback was _first_ registered, rather
  /// than the stack trace for when the callback is re-registered. This makes it
  /// easier to track down the original reason that a particular callback was
  /// called. If `rescheduling` is true, the call must be in the context of a
  /// frame callback.
  ///
  /// Callbacks registered with this method can be canceled using
  /// [cancelFrameCallbackWithId].
  ///
  /// See also:
  ///
  ///  * [WidgetsBinding.drawFrame], which explains the phases of each frame
  ///    for those apps that use Flutter widgets (and where transient frame
  ///    callbacks fit into those phases).
  /// 中文:调度给定的瞬态帧回调。
  ///
  /// 中文:将给定的回调添加到帧回调列表中,并确保帧被调度。
  ///
  /// 中文:如果这是在帧的动画阶段调用的(当瞬态帧回调仍在被调用时),
  /// 中文:将会调度一个新帧,并且`callback`将在新调度的帧中被调用,
  /// 中文:而不是在当前帧中。
  ///
  /// 中文:如果这是一次性注册,忽略`rescheduling`参数。
  ///
  /// 中文:如果这是一个每次触发时都会重新注册的回调,那么
  /// 中文:当你重新注册回调时,将`rescheduling`参数设置为
  /// 中文:true。这在发布构建中没有效果,但在调试构建中,它
  /// 中文:确保为此回调存储的堆栈跟踪是回调_首次_注册时的
  /// 中文:原始堆栈跟踪,而不是回调被重新注册时的堆栈跟踪。
  /// 中文:这使得更容易追踪特定回调被调用的原始原因。
  /// 中文:如果`rescheduling`为true,调用必须在帧回调的上下文中。
  ///
  /// 中文:使用此方法注册的回调可以使用[cancelFrameCallbackWithId]取消。
  ///
  /// 中文:另请参阅:
  ///
  /// 中文: * [WidgetsBinding.drawFrame],它解释了使用Flutter小部件的应用程序
  /// 中文:   每帧的各个阶段(以及瞬态帧回调适合这些阶段的位置)。
  int scheduleFrameCallback(FrameCallback callback, { bool rescheduling = false }) {
    scheduleFrame();
    _nextFrameCallbackId += 1;
    _transientCallbacks[_nextFrameCallbackId] = _FrameCallbackEntry(callback, rescheduling: rescheduling);
    return _nextFrameCallbackId;
  }

  /// Cancels the transient frame callback with the given [id].
  ///
  /// Removes the given callback from the list of frame callbacks. If a frame
  /// has been requested, this does not also cancel that request.
  ///
  /// Transient frame callbacks are those registered using
  /// [scheduleFrameCallback].
  /// 中文:取消具有给定[id]的瞬态帧回调。
  ///
  /// 中文:从帧回调列表中删除给定的回调。如果已经请求了一帧,
  /// 中文:这不会同时取消该请求。
  ///
  /// 中文:瞬态帧回调是使用[scheduleFrameCallback]注册的回调。
  void cancelFrameCallbackWithId(int id) {
    assert(id > 0);
    _transientCallbacks.remove(id);
    _removedIds.add(id);
  }
arduino 复制代码
  /// Asserts that there are no registered transient callbacks; if
  /// there are, prints their locations and throws an exception.
  ///
  /// A transient frame callback is one that was registered with
  /// [scheduleFrameCallback].
  ///
  /// This is expected to be called at the end of tests (the
  /// flutter_test framework does it automatically in normal cases).
  ///
  /// Call this method when you expect there to be no transient
  /// callbacks registered, in an assert statement with a message that
  /// you want printed when a transient callback is registered:
  ///
  /// ```dart
  /// assert(SchedulerBinding.instance.debugAssertNoTransientCallbacks(
  ///   'A leak of transient callbacks was detected while doing foo.'
  /// ));
  /// ```
  ///
  /// Does nothing if asserts are disabled. Always returns true.
  /// 中文:断言没有注册的瞬态回调;如果
  /// 中文:有,打印它们的位置并抛出异常。
  ///
  /// 中文:瞬态帧回调是使用[scheduleFrameCallback]注册的回调。
  ///
  /// 中文:这预期在测试结束时调用(flutter_test框架在正常情况下会自动执行)。
  ///
  /// 中文:当你期望没有瞬态回调注册时,在断言语句中调用此方法,
  /// 中文:并带有你希望在瞬态回调被注册时打印的消息:
  ///
  /// ```dart
  /// assert(SchedulerBinding.instance.debugAssertNoTransientCallbacks(
  ///   '在执行foo时检测到瞬态回调泄漏。'
  /// ));
  /// ```
  ///
  /// 中文:如果断言被禁用,则不执行任何操作。始终返回true。
  bool debugAssertNoTransientCallbacks(String reason) {
    assert(() {
      if (transientCallbackCount > 0) {
        // We cache the values so that we can produce them later
        // even if the information collector is called after
        // the problem has been resolved.
        // 中文:我们缓存这些值,以便稍后可以生成它们
        // 中文:即使信息收集器在问题解决后被调用。
        final int count = transientCallbackCount;
        final Map<int, _FrameCallbackEntry> callbacks = Map<int, _FrameCallbackEntry>.of(_transientCallbacks);
        FlutterError.reportError(FlutterErrorDetails(
          exception: reason,
          library: 'scheduler library',
          informationCollector: () => <DiagnosticsNode>[
            if (count == 1)
              // TODO(jacobr): I have added an extra line break in this case.
              // 中文:TODO(jacobr): 我在这种情况下添加了一个额外的换行符。
              ErrorDescription(
                'There was one transient callback left. '
                'The stack trace for when it was registered is as follows:',
                // 中文:有一个瞬态回调剩余。
                // 中文:它注册时的堆栈跟踪如下:
              )
            else
              ErrorDescription(
                'There were $count transient callbacks left. '
                'The stack traces for when they were registered are as follows:',
                // 中文:有$count个瞬态回调剩余。
                // 中文:它们注册时的堆栈跟踪如下:
              ),
            for (final int id in callbacks.keys)
              DiagnosticsStackTrace('── callback $id ──', callbacks[id]!.debugStack, showSeparator: false),
          ],
        ));
      }
      return true;
    }());
    return true;
  }

  /// Asserts that there are no pending performance mode requests in debug mode.
  ///
  /// Throws a [FlutterError] if there are pending performance mode requests,
  /// as this indicates a potential memory leak.
  /// 中文:在调试模式下断言没有待处理的性能模式请求。
  ///
  /// 中文:如果有待处理的性能模式请求,则抛出[FlutterError],
  /// 中文:因为这表明潜在的内存泄漏。
  bool debugAssertNoPendingPerformanceModeRequests(String reason) {
    assert(() {
      if (_performanceMode != null) {
        throw FlutterError(reason);
      }
      return true;
    }());
    return true;
  }

  /// Asserts that there is no artificial time dilation in debug mode.
  ///
  /// Throws a [FlutterError] if there are such dilation, as this will make
  /// subsequent tests see dilation and thus flaky.
  /// 中文:在调试模式下断言没有人为的时间膨胀。
  ///
  /// 中文:如果有这样的膨胀,则抛出[FlutterError],因为这会使
  /// 中文:后续测试看到膨胀,从而变得不稳定。
  bool debugAssertNoTimeDilation(String reason) {
    assert(() {
      if (timeDilation != 1.0) {
        throw FlutterError(reason);
      }
      return true;
    }());
    return true;
  }
scss 复制代码
  /// Prints the stack for where the current transient callback was registered.
  ///
  /// A transient frame callback is one that was registered with
  /// [scheduleFrameCallback].
  ///
  /// When called in debug more and in the context of a transient callback, this
  /// function prints the stack trace from where the current transient callback
  /// was registered (i.e. where it first called [scheduleFrameCallback]).
  ///
  /// When called in debug mode in other contexts, it prints a message saying
  /// that this function was not called in the context a transient callback.
  ///
  /// In release mode, this function does nothing.
  ///
  /// To call this function, use the following code:
  ///
  /// ```dart
  /// SchedulerBinding.debugPrintTransientCallbackRegistrationStack();
  /// ```
  /// 中文:打印当前瞬态回调注册位置的堆栈。
  ///
  /// 中文:瞬态帧回调是使用[scheduleFrameCallback]注册的回调。
  ///
  /// 中文:当在调试模式下并在瞬态回调的上下文中调用时,此
  /// 中文:函数打印当前瞬态回调注册位置的堆栈跟踪
  /// 中文:(即它首次调用[scheduleFrameCallback]的位置)。
  ///
  /// 中文:当在调试模式下在其他上下文中调用时,它打印一条消息,说明
  /// 中文:此函数不是在瞬态回调的上下文中调用的。
  ///
  /// 中文:在发布模式下,此函数不执行任何操作。
  ///
  /// 中文:要调用此函数,请使用以下代码:
  ///
  /// ```dart
  /// SchedulerBinding.debugPrintTransientCallbackRegistrationStack();
  /// ```
  static void debugPrintTransientCallbackRegistrationStack() {
    assert(() {
      if (_FrameCallbackEntry.debugCurrentCallbackStack != null) {
        debugPrint('When the current transient callback was registered, this was the stack:');
        // 中文:当前瞬态回调注册时,这是堆栈:
        debugPrint(
          FlutterError.defaultStackFilter(
            FlutterError.demangleStackTrace(
              _FrameCallbackEntry.debugCurrentCallbackStack!,
            ).toString().trimRight().split('\n'),
          ).join('\n'),
        );
      } else {
        debugPrint('No transient callback is currently executing.');
        // 中文:当前没有瞬态回调正在执行。
      }
      return true;
    }());
  }

  final List<FrameCallback> _persistentCallbacks = <FrameCallback>[];

  /// Adds a persistent frame callback.
  ///
  /// Persistent callbacks are called after transient
  /// (non-persistent) frame callbacks.
  ///
  /// Does *not* request a new frame. Conceptually, persistent frame
  /// callbacks are observers of "begin frame" events. Since they are
  /// executed after the transient frame callbacks they can drive the
  /// rendering pipeline.
  ///
  /// Persistent frame callbacks cannot be unregistered. Once registered, they
  /// are called for every frame for the lifetime of the application.
  ///
  /// See also:
  ///
  ///  * [WidgetsBinding.drawFrame], which explains the phases of each frame
  ///    for those apps that use Flutter widgets (and where persistent frame
  ///    callbacks fit into those phases).
  /// 中文:添加持久帧回调。
  ///
  /// 中文:持久回调在瞬态(非持久)帧回调之后调用。
  ///
  /// 中文:*不*请求新帧。从概念上讲,持久帧回调是"开始帧"事件的观察者。
  /// 中文:由于它们在瞬态帧回调之后执行,它们可以驱动渲染管道。
  ///
  /// 中文:持久帧回调不能被注销。一旦注册,它们将在应用程序的生命周期内
  /// 中文:为每一帧调用。
  ///
  /// 中文:另请参阅:
  ///
  /// 中文: * [WidgetsBinding.drawFrame],它解释了使用Flutter小部件的应用程序
  /// 中文:   每帧的各个阶段(以及持久帧回调适合这些阶段的位置)。
  void addPersistentFrameCallback(FrameCallback callback) {
    _persistentCallbacks.add(callback);
  }

  final List<FrameCallback> _postFrameCallbacks = <FrameCallback>[];

  /// Schedule a callback for the end of this frame.
  ///
  /// The provided callback is run immediately after a frame, just after the
  /// persistent frame callbacks (which is when the main rendering pipeline has
  /// been flushed).
  ///
  /// This method does *not* request a new frame. If a frame is already in
  /// progress and the execution of post-frame callbacks has not yet begun, then
  /// the registered callback is executed at the end of the current frame.
  /// Otherwise, the registered callback is executed after the next frame
  /// (whenever that may be, if ever).
  ///
  /// The callbacks are executed in the order in which they have been
  /// added.
  ///
  /// Post-frame callbacks cannot be unregistered. They are called exactly once.
  ///
  /// In debug mode, if [debugTracePostFrameCallbacks] is set to true, then the
  /// registered callback will show up in the timeline events chart, which can
  /// be viewed in [DevTools](https://docs.flutter.dev/tools/devtools).
  /// In that case, the `debugLabel` argument specifies the name of the callback
  /// as it will appear in the timeline. In profile and release builds,
  /// post-frame are never traced, and the `debugLabel` argument is ignored.
  ///
  /// See also:
  ///
  ///  * [scheduleFrameCallback], which registers a callback for the start of
  ///    the next frame.
  ///  * [WidgetsBinding.drawFrame], which explains the phases of each frame
  ///    for those apps that use Flutter widgets (and where post frame
  ///    callbacks fit into those phases).
  /// 中文:为此帧的结束调度回调。
  ///
  /// 中文:提供的回调在帧结束后立即运行,就在持久帧回调之后
  /// 中文:(这是主渲染管道已被刷新的时候)。
  ///
  /// 中文:此方法*不*请求新帧。如果帧已经在进行中,并且帧后回调的执行
  /// 中文:尚未开始,则注册的回调在当前帧结束时执行。
  /// 中文:否则,注册的回调在下一帧之后执行(如果有的话,无论何时)。
  ///
  /// 中文:回调按照添加的顺序执行。
  ///
  /// 中文:帧后回调不能被注销。它们只被调用一次。
  ///
  /// 中文:在调试模式下,如果[debugTracePostFrameCallbacks]设置为true,则
  /// 中文:注册的回调将显示在时间线事件图表中,可以在
  /// 中文:[DevTools](https://docs.flutter.dev/tools/devtools)中查看。
  /// 中文:在这种情况下,`debugLabel`参数指定回调在时间线中显示的名称。
  /// 中文:在配置文件和发布构建中,帧后回调永远不会被跟踪,并且`debugLabel`参数被忽略。
  ///
  /// 中文:另请参阅:
  ///
  /// 中文: * [scheduleFrameCallback],它为下一帧的开始注册回调。
  /// 中文: * [WidgetsBinding.drawFrame],它解释了使用Flutter小部件的应用程序
  /// 中文:   每帧的各个阶段(以及帧后回调适合这些阶段的位置)。
  void addPostFrameCallback(FrameCallback callback, {String debugLabel = 'callback'}) {
    assert(() {
      if (debugTracePostFrameCallbacks) {
        final FrameCallback originalCallback = callback;
        callback = (Duration timeStamp) {
          Timeline.startSync(debugLabel);
          try {
            originalCallback(timeStamp);
          } finally {
            Timeline.finishSync();
          }
        };
      }
      return true;
    }());
    _postFrameCallbacks.add(callback);
  }
csharp 复制代码
  Completer<void>? _nextFrameCompleter;

  /// Returns a Future that completes after the frame completes.
  ///
  /// If this is called between frames, a frame is immediately scheduled if
  /// necessary. If this is called during a frame, the Future completes after
  /// the current frame.
  ///
  /// If the device's screen is currently turned off, this may wait a very long
  /// time, since frames are not scheduled while the device's screen is turned
  /// off.
  /// 中文:返回一个在帧完成后完成的Future。
  ///
  /// 中文:如果这是在帧之间调用的,如果必要,会立即调度一帧。
  /// 中文:如果这是在帧期间调用的,Future在当前帧之后完成。
  ///
  /// 中文:如果设备的屏幕当前关闭,这可能会等待很长时间,
  /// 中文:因为在设备屏幕关闭时不会调度帧。
  Future<void> get endOfFrame {
    if (_nextFrameCompleter == null) {
      if (schedulerPhase == SchedulerPhase.idle) {
        scheduleFrame();
      }
      _nextFrameCompleter = Completer<void>();
      addPostFrameCallback((Duration timeStamp) {
        _nextFrameCompleter!.complete();
        _nextFrameCompleter = null;
      }, debugLabel: 'SchedulerBinding.completeFrame');
    }
    return _nextFrameCompleter!.future;
  }

  /// Whether this scheduler has requested that [handleBeginFrame] be called soon.
  /// 中文:此调度器是否已请求[handleBeginFrame]很快被调用。
  bool get hasScheduledFrame => _hasScheduledFrame;
  bool _hasScheduledFrame = false;

  /// The phase that the scheduler is currently operating under.
  /// 中文:调度器当前运行的阶段。
  SchedulerPhase get schedulerPhase => _schedulerPhase;
  SchedulerPhase _schedulerPhase = SchedulerPhase.idle;

  /// Whether frames are currently being scheduled when [scheduleFrame] is called.
  ///
  /// This value depends on the value of the [lifecycleState].
  /// 中文:当调用[scheduleFrame]时,帧当前是否正在被调度。
  ///
  /// 中文:此值取决于[lifecycleState]的值。
  bool get framesEnabled => _framesEnabled;

  bool _framesEnabled = true;
  void _setFramesEnabledState(bool enabled) {
    if (_framesEnabled == enabled) {
      return;
    }
    _framesEnabled = enabled;
    if (enabled) {
      scheduleFrame();
    }
  }

  /// Ensures callbacks for [PlatformDispatcher.onBeginFrame] and
  /// [PlatformDispatcher.onDrawFrame] are registered.
  /// 中文:确保[PlatformDispatcher.onBeginFrame]和
  /// 中文:[PlatformDispatcher.onDrawFrame]的回调已注册。
  @protected
  void ensureFrameCallbacksRegistered() {
    platformDispatcher.onBeginFrame ??= _handleBeginFrame;
    platformDispatcher.onDrawFrame ??= _handleDrawFrame;
  }

  /// Schedules a new frame using [scheduleFrame] if this object is not
  /// currently producing a frame.
  ///
  /// Calling this method ensures that [handleDrawFrame] will eventually be
  /// called, unless it's already in progress.
  ///
  /// This has no effect if [schedulerPhase] is
  /// [SchedulerPhase.transientCallbacks] or [SchedulerPhase.midFrameMicrotasks]
  /// (because a frame is already being prepared in that case), or
  /// [SchedulerPhase.persistentCallbacks] (because a frame is actively being
  /// rendered in that case). It will schedule a frame if the [schedulerPhase]
  /// is [SchedulerPhase.idle] (in between frames) or
  /// [SchedulerPhase.postFrameCallbacks] (after a frame).
  /// 中文:如果此对象当前没有产生帧,则使用[scheduleFrame]调度新帧。
  ///
  /// 中文:调用此方法确保[handleDrawFrame]最终会被调用,除非它已经在进行中。
  ///
  /// 中文:如果[schedulerPhase]是[SchedulerPhase.transientCallbacks]或
  /// 中文:[SchedulerPhase.midFrameMicrotasks](因为在这种情况下帧已经在准备中),
  /// 中文:或[SchedulerPhase.persistentCallbacks](因为在这种情况下帧正在积极
  /// 中文:被渲染),则此方法没有效果。如果[schedulerPhase]是[SchedulerPhase.idle]
  /// 中文:(在帧之间)或[SchedulerPhase.postFrameCallbacks](在帧之后),
  /// 中文:它将调度一帧。
  void ensureVisualUpdate() {
    switch (schedulerPhase) {
      case SchedulerPhase.idle:
      case SchedulerPhase.postFrameCallbacks:
        scheduleFrame();
        return;
      case SchedulerPhase.transientCallbacks:
      case SchedulerPhase.midFrameMicrotasks:
      case SchedulerPhase.persistentCallbacks:
        return;
    }
  }
scss 复制代码
  /// If necessary, schedules a new frame by calling
  /// [dart:ui.PlatformDispatcher.scheduleFrame].
  ///
  /// After this is called, the engine will (eventually) call
  /// [handleBeginFrame]. (This call might be delayed, e.g. if the device's
  /// screen is turned off it will typically be delayed until the screen is on
  /// and the application is visible.) Calling this during a frame forces
  /// another frame to be scheduled, even if the current frame has not yet
  /// completed.
  ///
  /// Scheduled frames are serviced when triggered by a "Vsync" signal provided
  /// by the operating system. The "Vsync" signal, or vertical synchronization
  /// signal, was historically related to the display refresh, at a time when
  /// hardware physically moved a beam of electrons vertically between updates
  /// of the display. The operation of contemporary hardware is somewhat more
  /// subtle and complicated, but the conceptual "Vsync" refresh signal continue
  /// to be used to indicate when applications should update their rendering.
  ///
  /// To have a stack trace printed to the console any time this function
  /// schedules a frame, set [debugPrintScheduleFrameStacks] to true.
  ///
  /// See also:
  ///
  ///  * [scheduleForcedFrame], which ignores the [lifecycleState] when
  ///    scheduling a frame.
  ///  * [scheduleWarmUpFrame], which ignores the "Vsync" signal entirely and
  ///    triggers a frame immediately.
  /// 中文:如有必要,通过调用[dart:ui.PlatformDispatcher.scheduleFrame]调度新帧。
  ///
  /// 中文:调用此方法后,引擎将(最终)调用[handleBeginFrame]。
  /// 中文:(此调用可能会延迟,例如,如果设备的屏幕关闭,通常会延迟到屏幕打开
  /// 中文:并且应用程序可见时。)在帧期间调用此方法会强制调度另一帧,
  /// 中文:即使当前帧尚未完成。
  ///
  /// 中文:调度的帧在由操作系统提供的"Vsync"信号触发时被服务。
  /// 中文:"Vsync"信号,或垂直同步信号,在历史上与显示刷新相关,
  /// 中文:在硬件物理上在显示更新之间垂直移动电子束的时候。
  /// 中文:现代硬件的操作有些更微妙和复杂,但概念上的"Vsync"刷新信号
  /// 中文:继续用于指示应用程序应该何时更新其渲染。
  ///
  /// 中文:要在此函数调度帧时将堆栈跟踪打印到控制台,
  /// 中文:请将[debugPrintScheduleFrameStacks]设置为true。
  ///
  /// 中文:另请参阅:
  ///
  /// 中文: * [scheduleForcedFrame],它在调度帧时忽略[lifecycleState]。
  /// 中文: * [scheduleWarmUpFrame],它完全忽略"Vsync"信号并立即触发帧。
  void scheduleFrame() {
    if (_hasScheduledFrame || !framesEnabled) {
      return;
    }
    assert(() {
      if (debugPrintScheduleFrameStacks) {
        debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.');
      }
      return true;
    }());
    ensureFrameCallbacksRegistered();
    platformDispatcher.scheduleFrame();
    _hasScheduledFrame = true;
  }

  /// Schedules a new frame by calling
  /// [dart:ui.PlatformDispatcher.scheduleFrame].
  ///
  /// After this is called, the engine will call [handleBeginFrame], even if
  /// frames would normally not be scheduled by [scheduleFrame] (e.g. even if
  /// the device's screen is turned off).
  ///
  /// The framework uses this to force a frame to be rendered at the correct
  /// size when the phone is rotated, so that a correctly-sized rendering is
  /// available when the screen is turned back on.
  ///
  /// To have a stack trace printed to the console any time this function
  /// schedules a frame, set [debugPrintScheduleFrameStacks] to true.
  ///
  /// Prefer using [scheduleFrame] unless it is imperative that a frame be
  /// scheduled immediately, since using [scheduleForcedFrame] will cause
  /// significantly higher battery usage when the device should be idle.
  ///
  /// Consider using [scheduleWarmUpFrame] instead if the goal is to update the
  /// rendering as soon as possible (e.g. at application startup).
  /// 中文:通过调用[dart:ui.PlatformDispatcher.scheduleFrame]调度新帧。
  ///
  /// 中文:调用此方法后,引擎将调用[handleBeginFrame],即使帧通常不会
  /// 中文:由[scheduleFrame]调度(例如,即使设备的屏幕关闭)。
  ///
  /// 中文:框架使用这个来强制在手机旋转时以正确的尺寸渲染帧,
  /// 中文:以便在屏幕重新打开时有正确尺寸的渲染可用。
  ///
  /// 中文:要在此函数调度帧时将堆栈跟踪打印到控制台,
  /// 中文:请将[debugPrintScheduleFrameStacks]设置为true。
  ///
  /// 中文:除非必须立即调度帧,否则优先使用[scheduleFrame],
  /// 中文:因为使用[scheduleForcedFrame]会在设备应该空闲时
  /// 中文:导致明显更高的电池使用率。
  ///
  /// 中文:如果目标是尽快更新渲染(例如在应用程序启动时),
  /// 中文:请考虑使用[scheduleWarmUpFrame]。
  void scheduleForcedFrame() {
    if (_hasScheduledFrame) {
      return;
    }
    assert(() {
      if (debugPrintScheduleFrameStacks) {
        debugPrintStack(label: 'scheduleForcedFrame() called. Current phase is $schedulerPhase.');
      }
      return true;
    }());
    ensureFrameCallbacksRegistered();
    platformDispatcher.scheduleFrame();
    _hasScheduledFrame = true;
  }
scss 复制代码
  /// If necessary, schedules a new frame by calling
  /// [dart:ui.PlatformDispatcher.scheduleFrame].
  ///
  /// After this is called, the engine will (eventually) call
  /// [handleBeginFrame]. (This call might be delayed, e.g. if the device's
  /// screen is turned off it will typically be delayed until the screen is on
  /// and the application is visible.) Calling this during a frame forces
  /// another frame to be scheduled, even if the current frame has not yet
  /// completed.
  ///
  /// Scheduled frames are serviced when triggered by a "Vsync" signal provided
  /// by the operating system. The "Vsync" signal, or vertical synchronization
  /// signal, was historically related to the display refresh, at a time when
  /// hardware physically moved a beam of electrons vertically between updates
  /// of the display. The operation of contemporary hardware is somewhat more
  /// subtle and complicated, but the conceptual "Vsync" refresh signal continue
  /// to be used to indicate when applications should update their rendering.
  ///
  /// To have a stack trace printed to the console any time this function
  /// schedules a frame, set [debugPrintScheduleFrameStacks] to true.
  ///
  /// See also:
  ///
  ///  * [scheduleForcedFrame], which ignores the [lifecycleState] when
  ///    scheduling a frame.
  ///  * [scheduleWarmUpFrame], which ignores the "Vsync" signal entirely and
  ///    triggers a frame immediately.
  /// 中文:如有必要,通过调用[dart:ui.PlatformDispatcher.scheduleFrame]调度新帧。
  ///
  /// 中文:调用此方法后,引擎将(最终)调用[handleBeginFrame]。
  /// 中文:(此调用可能会延迟,例如,如果设备的屏幕关闭,通常会延迟到屏幕打开
  /// 中文:并且应用程序可见时。)在帧期间调用此方法会强制调度另一帧,
  /// 中文:即使当前帧尚未完成。
  ///
  /// 中文:调度的帧在由操作系统提供的"Vsync"信号触发时被服务。
  /// 中文:"Vsync"信号,或垂直同步信号,在历史上与显示刷新相关,
  /// 中文:在硬件物理上在显示更新之间垂直移动电子束的时候。
  /// 中文:现代硬件的操作有些更微妙和复杂,但概念上的"Vsync"刷新信号
  /// 中文:继续用于指示应用程序应该何时更新其渲染。
  ///
  /// 中文:要在此函数调度帧时将堆栈跟踪打印到控制台,
  /// 中文:请将[debugPrintScheduleFrameStacks]设置为true。
  ///
  /// 中文:另请参阅:
  ///
  /// 中文: * [scheduleForcedFrame],它在调度帧时忽略[lifecycleState]。
  /// 中文: * [scheduleWarmUpFrame],它完全忽略"Vsync"信号并立即触发帧。
  void scheduleFrame() {
    if (_hasScheduledFrame || !framesEnabled) {
      return;
    }
    assert(() {
      if (debugPrintScheduleFrameStacks) {
        debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.');
      }
      return true;
    }());
    ensureFrameCallbacksRegistered();
    platformDispatcher.scheduleFrame();
    _hasScheduledFrame = true;
  }

  /// Schedules a new frame by calling
  /// [dart:ui.PlatformDispatcher.scheduleFrame].
  ///
  /// After this is called, the engine will call [handleBeginFrame], even if
  /// frames would normally not be scheduled by [scheduleFrame] (e.g. even if
  /// the device's screen is turned off).
  ///
  /// The framework uses this to force a frame to be rendered at the correct
  /// size when the phone is rotated, so that a correctly-sized rendering is
  /// available when the screen is turned back on.
  ///
  /// To have a stack trace printed to the console any time this function
  /// schedules a frame, set [debugPrintScheduleFrameStacks] to true.
  ///
  /// Prefer using [scheduleFrame] unless it is imperative that a frame be
  /// scheduled immediately, since using [scheduleForcedFrame] will cause
  /// significantly higher battery usage when the device should be idle.
  ///
  /// Consider using [scheduleWarmUpFrame] instead if the goal is to update the
  /// rendering as soon as possible (e.g. at application startup).
  /// 中文:通过调用[dart:ui.PlatformDispatcher.scheduleFrame]调度新帧。
  ///
  /// 中文:调用此方法后,引擎将调用[handleBeginFrame],即使帧通常不会
  /// 中文:由[scheduleFrame]调度(例如,即使设备的屏幕关闭)。
  ///
  /// 中文:框架使用这个来强制在手机旋转时以正确的尺寸渲染帧,
  /// 中文:以便在屏幕重新打开时有正确尺寸的渲染可用。
  ///
  /// 中文:要在此函数调度帧时将堆栈跟踪打印到控制台,
  /// 中文:请将[debugPrintScheduleFrameStacks]设置为true。
  ///
  /// 中文:除非必须立即调度帧,否则优先使用[scheduleFrame],
  /// 中文:因为使用[scheduleForcedFrame]会在设备应该空闲时
  /// 中文:导致明显更高的电池使用率。
  ///
  /// 中文:如果目标是尽快更新渲染(例如在应用程序启动时),
  /// 中文:请考虑使用[scheduleWarmUpFrame]。
  void scheduleForcedFrame() {
    if (_hasScheduledFrame) {
      return;
    }
    assert(() {
      if (debugPrintScheduleFrameStacks) {
        debugPrintStack(label: 'scheduleForcedFrame() called. Current phase is $schedulerPhase.');
      }
      return true;
    }());
    ensureFrameCallbacksRegistered();
    platformDispatcher.scheduleFrame();
    _hasScheduledFrame = true;
  }
scss 复制代码
  bool _warmUpFrame = false;

  /// Schedule a frame to run as soon as possible, rather than waiting for
  /// the engine to request a frame in response to a system "Vsync" signal.
  ///
  /// This is used during application startup so that the first frame (which is
  /// likely to be quite expensive) gets a few extra milliseconds to run.
  ///
  /// Locks events dispatching until the scheduled frame has completed.
  ///
  /// If a frame has already been scheduled with [scheduleFrame] or
  /// [scheduleForcedFrame], this call may delay that frame.
  ///
  /// If any scheduled frame has already begun or if another
  /// [scheduleWarmUpFrame] was already called, this call will be ignored.
  ///
  /// Prefer [scheduleFrame] to update the display in normal operation.
  ///
  /// ## Design discussion
  ///
  /// The Flutter engine prompts the framework to generate frames when it
  /// receives a request from the operating system (known for historical reasons
  /// as a vsync). However, this may not happen for several milliseconds after
  /// the app starts (or after a hot reload). To make use of the time between
  /// when the widget tree is first configured and when the engine requests an
  /// update, the framework schedules a _warm-up frame_.
  ///
  /// A warm-up frame may never actually render (as the engine did not request
  /// it and therefore does not have a valid context in which to paint), but it
  /// will cause the framework to go through the steps of building, laying out,
  /// and painting, which can together take several milliseconds. Thus, when the
  /// engine requests a real frame, much of the work will already have been
  /// completed, and the framework can generate the frame with minimal
  /// additional effort.
  ///
  /// Warm-up frames are scheduled by [runApp] on startup, and by
  /// [RendererBinding.performReassemble] during a hot reload.
  ///
  /// Warm-up frames are also scheduled when the framework is unblocked by a
  /// call to [RendererBinding.allowFirstFrame] (corresponding to a call to
  /// [RendererBinding.deferFirstFrame] that blocked the rendering).
  /// 中文:调度一个尽快运行的帧,而不是等待引擎响应系统"Vsync"信号请求帧。
  ///
  /// 中文:这在应用程序启动期间使用,以便第一帧(可能相当昂贵)
  /// 中文:获得几毫秒的额外运行时间。
  ///
  /// 中文:锁定事件分派,直到调度的帧完成。
  ///
  /// 中文:如果已经使用[scheduleFrame]或[scheduleForcedFrame]调度了帧,
  /// 中文:此调用可能会延迟该帧。
  ///
  /// 中文:如果任何调度的帧已经开始,或者另一个[scheduleWarmUpFrame]
  /// 中文:已经被调用,此调用将被忽略。
  ///
  /// 中文:在正常操作中,优先使用[scheduleFrame]更新显示。
  ///
  /// 中文:## 设计讨论
  ///
  /// 中文:Flutter引擎在收到来自操作系统的请求(由于历史原因称为vsync)时,
  /// 中文:提示框架生成帧。然而,这可能在应用程序启动(或热重载)后
  /// 中文:几毫秒内不会发生。为了利用小部件树首次配置和引擎请求
  /// 中文:更新之间的时间,框架调度了一个_预热帧_。
  ///
  /// 中文:预热帧可能永远不会真正渲染(因为引擎没有请求它,
  /// 中文:因此没有有效的上下文进行绘制),但它会使框架经历构建、布局
  /// 中文:和绘制的步骤,这些步骤加起来可能需要几毫秒。因此,当引擎
  /// 中文:请求真实帧时,大部分工作已经完成,框架可以以最小的
  /// 中文:额外努力生成帧。
  ///
  /// 中文:预热帧由[runApp]在启动时调度,并由
  /// 中文:[RendererBinding.performReassemble]在热重载期间调度。
  ///
  /// 中文:当框架被调用[RendererBinding.allowFirstFrame]解除阻塞时
  /// 中文:(对应于调用[RendererBinding.deferFirstFrame]阻塞渲染),
  /// 中文:也会调度预热帧。
  void scheduleWarmUpFrame() {
    if (_warmUpFrame || schedulerPhase != SchedulerPhase.idle) {
      return;
    }

    _warmUpFrame = true;
    TimelineTask? debugTimelineTask;
    if (!kReleaseMode) {
      debugTimelineTask = TimelineTask()..start('Warm-up frame');
    }
    final bool hadScheduledFrame = _hasScheduledFrame;
    PlatformDispatcher.instance.scheduleWarmUpFrame(
      beginFrame: () {
        assert(_warmUpFrame);
        handleBeginFrame(null);
      },
      drawFrame: () {
        assert(_warmUpFrame);
        handleDrawFrame();
        // We call resetEpoch after this frame so that, in the hot reload case,
        // the very next frame pretends to have occurred immediately after this
        // warm-up frame. The warm-up frame's timestamp will typically be far in
        // the past (the time of the last real frame), so if we didn't reset the
        // epoch we would see a sudden jump from the old time in the warm-up frame
        // to the new time in the "real" frame. The biggest problem with this is
        // that implicit animations end up being triggered at the old time and
        // then skipping every frame and finishing in the new time.
        // 中文:我们在此帧之后调用resetEpoch,以便在热重载的情况下,
        // 中文:下一帧假装在此预热帧之后立即发生。预热帧的时间戳通常
        // 中文:会远在过去(上一个真实帧的时间),所以如果我们不重置纪元,
        // 中文:我们会看到从预热帧中的旧时间到"真实"帧中的新时间的突然跳跃。
        // 中文:最大的问题是隐式动画最终在旧时间被触发,然后跳过每一帧
        // 中文:并在新时间完成。
        resetEpoch();
        _warmUpFrame = false;
        if (hadScheduledFrame) {
          scheduleFrame();
        }
      },
    );

    // Lock events so touch events etc don't insert themselves until the
    // scheduled frame has finished.
    // 中文:锁定事件,以便触摸事件等不会插入,直到调度的帧完成。
    lockEvents(() async {
      await endOfFrame;
      if (!kReleaseMode) {
        debugTimelineTask!.finish();
      }
    });
  }
java 复制代码
  Duration? _firstRawTimeStampInEpoch;
  Duration _epochStart = Duration.zero;
  Duration _lastRawTimeStamp = Duration.zero;

  /// Prepares the scheduler for a non-monotonic change to how time stamps are
  /// calculated.
  ///
  /// Callbacks received from the scheduler assume that their time stamps are
  /// monotonically increasing. The raw time stamp passed to [handleBeginFrame]
  /// is monotonic, but the scheduler might adjust those time stamps to provide
  /// [timeDilation]. Without careful handling, these adjusts could cause time
  /// to appear to run backwards.
  ///
  /// The [resetEpoch] function ensures that the time stamps are monotonic by
  /// resetting the base time stamp used for future time stamp adjustments to the
  /// current value. For example, if the [timeDilation] decreases, rather than
  /// scaling down the [Duration] since the beginning of time, [resetEpoch] will
  /// ensure that we only scale down the duration since [resetEpoch] was called.
  ///
  /// Setting [timeDilation] calls [resetEpoch] automatically. You don't need to
  /// call [resetEpoch] yourself.
  /// 中文:准备调度器进行时间戳计算方式的非单调变化。
  ///
  /// 中文:从调度器接收的回调假设它们的时间戳是单调递增的。
  /// 中文:传递给[handleBeginFrame]的原始时间戳是单调的,但调度器
  /// 中文:可能会调整这些时间戳以提供[timeDilation]。如果不仔细处理,
  /// 中文:这些调整可能导致时间看起来向后运行。
  ///
  /// 中文:[resetEpoch]函数通过重置用于未来时间戳调整的基础时间戳
  /// 中文:为当前值,确保时间戳是单调的。例如,如果[timeDilation]减小,
  /// 中文:[resetEpoch]将确保我们只缩小自[resetEpoch]被调用以来的持续时间,
  /// 中文:而不是从时间开始以来的[Duration]。
  ///
  /// 中文:设置[timeDilation]会自动调用[resetEpoch]。你不需要
  /// 中文:自己调用[resetEpoch]。
  void resetEpoch() {
    _epochStart = _adjustForEpoch(_lastRawTimeStamp);
    _firstRawTimeStampInEpoch = null;
  }

  /// Adjusts the given time stamp into the current epoch.
  ///
  /// This both offsets the time stamp to account for when the epoch started
  /// (both in raw time and in the epoch's own time line) and scales the time
  /// stamp to reflect the time dilation in the current epoch.
  ///
  /// These mechanisms together combine to ensure that the durations we give
  /// during frame callbacks are monotonically increasing.
  /// 中文:将给定的时间戳调整到当前纪元。
  ///
  /// 中文:这既偏移时间戳以考虑纪元开始的时间
  /// 中文:(在原始时间和纪元自己的时间线中),又缩放时间戳
  /// 中文:以反映当前纪元中的时间膨胀。
  ///
  /// 中文:这些机制共同确保我们在帧回调期间给出的持续时间是单调递增的。
  Duration _adjustForEpoch(Duration rawTimeStamp) {
    final Duration rawDurationSinceEpoch = _firstRawTimeStampInEpoch == null ? Duration.zero : rawTimeStamp - _firstRawTimeStampInEpoch!;
    return Duration(microseconds: (rawDurationSinceEpoch.inMicroseconds / timeDilation).round() + _epochStart.inMicroseconds);
  }

  /// The time stamp for the frame currently being processed.
  ///
  /// This is only valid while between the start of [handleBeginFrame] and the
  /// end of the corresponding [handleDrawFrame], i.e. while a frame is being
  /// produced.
  /// 中文:当前正在处理的帧的时间戳。
  ///
  /// 中文:这仅在[handleBeginFrame]的开始和相应的[handleDrawFrame]的
  /// 中文:结束之间有效,即在产生帧时。
  Duration get currentFrameTimeStamp {
    assert(_currentFrameTimeStamp != null);
    return _currentFrameTimeStamp!;
  }
  Duration? _currentFrameTimeStamp;

  /// The raw time stamp as provided by the engine to
  /// [dart:ui.PlatformDispatcher.onBeginFrame] for the frame currently being
  /// processed.
  ///
  /// Unlike [currentFrameTimeStamp], this time stamp is neither adjusted to
  /// offset when the epoch started nor scaled to reflect the [timeDilation] in
  /// the current epoch.
  ///
  /// On most platforms, this is a more or less arbitrary value, and should
  /// generally be ignored. On Fuchsia, this corresponds to the system-provided
  /// presentation time, and can be used to ensure that animations running in
  /// different processes are synchronized.
  /// 中文:引擎提供给[dart:ui.PlatformDispatcher.onBeginFrame]的
  /// 中文:当前正在处理的帧的原始时间戳。
  ///
  /// 中文:与[currentFrameTimeStamp]不同,此时间戳既不调整为
  /// 中文:偏移纪元开始的时间,也不缩放以反映当前纪元中的[timeDilation]。
  ///
  /// 中文:在大多数平台上,这是一个或多或少的任意值,通常应该被忽略。
  /// 中文:在Fuchsia上,这对应于系统提供的呈现时间,可用于确保
  /// 中文:在不同进程中运行的动画是同步的。
  Duration get currentSystemFrameTimeStamp {
    return _lastRawTimeStamp;
  }

  int _debugFrameNumber = 0;
  String? _debugBanner;

  // Whether the current engine frame needs to be postponed till after the
  // warm-up frame.
  //
  // Engine may begin a frame in the middle of the warm-up frame because the
  // warm-up frame is scheduled by timers while the engine frame is scheduled
  // by platform specific frame scheduler (e.g. `requestAnimationFrame` on the
  // web). When this happens, we let the warm-up frame finish, and postpone the
  // engine frame.
  // 中文:当前引擎帧是否需要推迟到预热帧之后。
  //
  // 中文:引擎可能在预热帧中间开始一帧,因为预热帧是由计时器调度的,
  // 中文:而引擎帧是由平台特定的帧调度器调度的(例如,在网络上的
  // 中文:`requestAnimationFrame`)。当这种情况发生时,我们让预热帧
  // 中文:完成,并推迟引擎帧。
  bool _rescheduleAfterWarmUpFrame = false;

  void _handleBeginFrame(Duration rawTimeStamp) {
    if (_warmUpFrame) {
      // "begin frame" and "draw frame" must strictly alternate. Therefore
      // _rescheduleAfterWarmUpFrame cannot possibly be true here as it is
      // reset by _handleDrawFrame.
      // 中文:"begin frame"和"draw frame"必须严格交替。因此
      // 中文:_rescheduleAfterWarmUpFrame不可能在这里为true,因为它
      // 中文:被_handleDrawFrame重置。
      assert(!_rescheduleAfterWarmUpFrame);
      _rescheduleAfterWarmUpFrame = true;
      return;
    }
    handleBeginFrame(rawTimeStamp);
  }

  void _handleDrawFrame() {
    if (_rescheduleAfterWarmUpFrame) {
      _rescheduleAfterWarmUpFrame = false;
      // Reschedule in a post-frame callback to allow the draw-frame phase of
      // the warm-up frame to finish.
      // 中文:在帧后回调中重新调度,以允许预热帧的draw-frame阶段完成。
      addPostFrameCallback((Duration timeStamp) {
        // Force an engine frame.
        //
        // We need to reset _hasScheduledFrame here because we cancelled the
        // original engine frame, and therefore did not run handleBeginFrame
        // who is responsible for resetting it. So if a frame callback set this
        // to true in the "begin frame" part of the warm-up frame, it will
        // still be true here and cause us to skip scheduling an engine frame.
        // 中文:强制引擎帧。
        //
        // 中文:我们需要在这里重置_hasScheduledFrame,因为我们取消了
        // 中文:原始引擎帧,因此没有运行负责重置它的handleBeginFrame。
        // 中文:所以如果帧回调在预热帧的"begin frame"部分将其设置为true,
        // 中文:它在这里仍然为true,并导致我们跳过调度引擎帧。
        _hasScheduledFrame = false;
        scheduleFrame();
      }, debugLabel: 'SchedulerBinding.scheduleFrame');
      return;
    }
    handleDrawFrame();
  }

  final TimelineTask? _frameTimelineTask = kReleaseMode ? null : TimelineTask();
scss 复制代码
  /// Called by the engine to prepare the framework to produce a new frame.
  ///
  /// This function calls all the transient frame callbacks registered by
  /// [scheduleFrameCallback]. It then returns, any scheduled microtasks are run
  /// (e.g. handlers for any [Future]s resolved by transient frame callbacks),
  /// and [handleDrawFrame] is called to continue the frame.
  ///
  /// If the given time stamp is null, the time stamp from the last frame is
  /// reused.
  ///
  /// To have a banner shown at the start of every frame in debug mode, set
  /// [debugPrintBeginFrameBanner] to true. The banner will be printed to the
  /// console using [debugPrint] and will contain the frame number (which
  /// increments by one for each frame), and the time stamp of the frame. If the
  /// given time stamp was null, then the string "warm-up frame" is shown
  /// instead of the time stamp. This allows frames eagerly pushed by the
  /// framework to be distinguished from those requested by the engine in
  /// response to the "Vsync" signal from the operating system.
  ///
  /// You can also show a banner at the end of every frame by setting
  /// [debugPrintEndFrameBanner] to true. This allows you to distinguish log
  /// statements printed during a frame from those printed between frames (e.g.
  /// in response to events or timers).
  /// 中文:由引擎调用,准备框架产生新帧。
  ///
  /// 中文:此函数调用由[scheduleFrameCallback]注册的所有瞬态帧回调。
  /// 中文:然后它返回,运行任何调度的微任务(例如,由瞬态帧回调解析的
  /// 中文:任何[Future]的处理程序),并调用[handleDrawFrame]继续帧。
  ///
  /// 中文:如果给定的时间戳为null,则重用上一帧的时间戳。
  ///
  /// 中文:要在调试模式下在每帧开始时显示横幅,请设置
  /// 中文:[debugPrintBeginFrameBanner]为true。横幅将使用[debugPrint]
  /// 中文:打印到控制台,并将包含帧号(每帧递增一个)和帧的时间戳。
  /// 中文:如果给定的时间戳为null,则显示字符串"warm-up frame"
  /// 中文:而不是时间戳。这允许区分框架急切推送的帧和引擎响应
  /// 中文:操作系统的"Vsync"信号请求的帧。
  ///
  /// 中文:你也可以通过设置[debugPrintEndFrameBanner]为true在每帧结束时
  /// 中文:显示横幅。这允许你区分在帧期间打印的日志语句和在帧之间
  /// 中文:打印的日志语句(例如,响应事件或计时器)。
  void handleBeginFrame(Duration? rawTimeStamp) {
    _frameTimelineTask?.start('Frame');
    _firstRawTimeStampInEpoch ??= rawTimeStamp;
    _currentFrameTimeStamp = _adjustForEpoch(rawTimeStamp ?? _lastRawTimeStamp);
    if (rawTimeStamp != null) {
      _lastRawTimeStamp = rawTimeStamp;
    }

    assert(() {
      _debugFrameNumber += 1;

      if (debugPrintBeginFrameBanner || debugPrintEndFrameBanner) {
        final StringBuffer frameTimeStampDescription = StringBuffer();
        if (rawTimeStamp != null) {
          _debugDescribeTimeStamp(_currentFrameTimeStamp!, frameTimeStampDescription);
        } else {
          frameTimeStampDescription.write('(warm-up frame)');
        }
        _debugBanner = '▄▄▄▄▄▄▄▄ Frame ${_debugFrameNumber.toString().padRight(7)}   ${frameTimeStampDescription.toString().padLeft(18)} ▄▄▄▄▄▄▄▄';
        if (debugPrintBeginFrameBanner) {
          debugPrint(_debugBanner);
        }
      }
      return true;
    }());

    assert(schedulerPhase == SchedulerPhase.idle);
    _hasScheduledFrame = false;
    try {
      // TRANSIENT FRAME CALLBACKS
      // 中文:瞬态帧回调
      _frameTimelineTask?.start('Animate');
      _schedulerPhase = SchedulerPhase.transientCallbacks;
      final Map<int, _FrameCallbackEntry> callbacks = _transientCallbacks;
      _transientCallbacks = <int, _FrameCallbackEntry>{};
      callbacks.forEach((int id, _FrameCallbackEntry callbackEntry) {
        if (!_removedIds.contains(id)) {
          _invokeFrameCallback(callbackEntry.callback, _currentFrameTimeStamp!, callbackEntry.debugStack);
        }
      });
      _removedIds.clear();
    } finally {
      _schedulerPhase = SchedulerPhase.midFrameMicrotasks;
    }
  }

  DartPerformanceMode? _performanceMode;
  int _numPerformanceModeRequests = 0;

  /// Request a specific [DartPerformanceMode].
  ///
  /// Returns `null` if the request was not successful due to conflicting performance mode requests.
  /// Two requests are said to be in conflict if they are not of the same [DartPerformanceMode] type,
  /// and an explicit request for a performance mode has been made prior.
  ///
  /// Requestor is responsible for calling [PerformanceModeRequestHandle.dispose] when it no longer
  /// requires the performance mode.
  /// 中文:请求特定的[DartPerformanceMode]。
  ///
  /// 中文:如果由于冲突的性能模式请求而导致请求不成功,则返回`null`。
  /// 中文:如果两个请求不是相同的[DartPerformanceMode]类型,
  /// 中文:并且之前已经明确请求了性能模式,则称它们冲突。
  ///
  /// 中文:请求者负责在不再需要性能模式时调用[PerformanceModeRequestHandle.dispose]。
  PerformanceModeRequestHandle? requestPerformanceMode(DartPerformanceMode mode) {
    // conflicting requests are not allowed.
    // 中文:不允许冲突的请求。
    if (_performanceMode != null && _performanceMode != mode) {
      return null;
    }

    if (_performanceMode == mode) {
      assert(_numPerformanceModeRequests > 0);
      _numPerformanceModeRequests++;
    } else if (_performanceMode == null) {
      assert(_numPerformanceModeRequests == 0);
      _performanceMode = mode;
      _numPerformanceModeRequests = 1;
    }

    return PerformanceModeRequestHandle._(_disposePerformanceModeRequest);
  }

  /// Remove a request for a specific [DartPerformanceMode].
  ///
  /// If all the pending requests have been disposed, the engine will revert to the
  /// [DartPerformanceMode.balanced] performance mode.
  /// 中文:删除对特定[DartPerformanceMode]的请求。
  ///
  /// 中文:如果所有待处理的请求都已处置,引擎将恢复为
  /// 中文:[DartPerformanceMode.balanced]性能模式。
  void _disposePerformanceModeRequest() {
    _numPerformanceModeRequests--;
    if (_numPerformanceModeRequests == 0) {
      _performanceMode = null;
      PlatformDispatcher.instance.requestDartPerformanceMode(DartPerformanceMode.balanced);
    }
  }
scss 复制代码
  /// Returns the current [DartPerformanceMode] requested or `null` if no requests have
  /// been made.
  ///
  /// This is only supported in debug and profile modes, returns `null` in release mode.
  /// 中文:返回当前请求的[DartPerformanceMode],如果没有请求,则返回`null`。
  ///
  /// 中文:这仅在调试和配置文件模式下支持,在发布模式下返回`null`。
  DartPerformanceMode? debugGetRequestedPerformanceMode() {
    if (!(kDebugMode || kProfileMode)) {
      return null;
    } else {
      return _performanceMode;
    }
  }

  /// Called by the engine to produce a new frame.
  ///
  /// This method is called immediately after [handleBeginFrame]. It calls all
  /// the callbacks registered by [addPersistentFrameCallback], which typically
  /// drive the rendering pipeline, and then calls the callbacks registered by
  /// [addPostFrameCallback].
  ///
  /// See [handleBeginFrame] for a discussion about debugging hooks that may be
  /// useful when working with frame callbacks.
  /// 中文:由引擎调用以产生新帧。
  ///
  /// 中文:此方法在[handleBeginFrame]之后立即调用。它调用所有
  /// 中文:由[addPersistentFrameCallback]注册的回调,这些回调通常
  /// 中文:驱动渲染管道,然后调用由[addPostFrameCallback]注册的回调。
  ///
  /// 中文:有关处理帧回调时可能有用的调试钩子的讨论,请参见[handleBeginFrame]。
  void handleDrawFrame() {
    assert(_schedulerPhase == SchedulerPhase.midFrameMicrotasks);
    _frameTimelineTask?.finish(); // end the "Animate" phase
    try {
      // PERSISTENT FRAME CALLBACKS
      // 中文:持久帧回调
      _schedulerPhase = SchedulerPhase.persistentCallbacks;
      for (final FrameCallback callback in List<FrameCallback>.of(_persistentCallbacks)) {
        _invokeFrameCallback(callback, _currentFrameTimeStamp!);
      }

      // POST-FRAME CALLBACKS
      // 中文:帧后回调
      _schedulerPhase = SchedulerPhase.postFrameCallbacks;
      final List<FrameCallback> localPostFrameCallbacks =
          List<FrameCallback>.of(_postFrameCallbacks);
      _postFrameCallbacks.clear();
      if (!kReleaseMode) {
        FlutterTimeline.startSync('POST_FRAME');
      }
      try {
        for (final FrameCallback callback in localPostFrameCallbacks) {
          _invokeFrameCallback(callback, _currentFrameTimeStamp!);
        }
      } finally {
        if (!kReleaseMode) {
          FlutterTimeline.finishSync();
        }
      }
    } finally {
      _schedulerPhase = SchedulerPhase.idle;
      _frameTimelineTask?.finish(); // end the Frame
      assert(() {
        if (debugPrintEndFrameBanner) {
          debugPrint('▀' * _debugBanner!.length);
        }
        _debugBanner = null;
        return true;
      }());
      _currentFrameTimeStamp = null;
    }
  }

  void _profileFramePostEvent(FrameTiming frameTiming) {
    postEvent('Flutter.Frame', <String, dynamic>{
      'number': frameTiming.frameNumber,
      'startTime': frameTiming.timestampInMicroseconds(FramePhase.buildStart),
      'elapsed': frameTiming.totalSpan.inMicroseconds,
      'build': frameTiming.buildDuration.inMicroseconds,
      'raster': frameTiming.rasterDuration.inMicroseconds,
      'vsyncOverhead': frameTiming.vsyncOverhead.inMicroseconds,
    });
  }

  static void _debugDescribeTimeStamp(Duration timeStamp, StringBuffer buffer) {
    if (timeStamp.inDays > 0) {
      buffer.write('${timeStamp.inDays}d ');
    }
    if (timeStamp.inHours > 0) {
      buffer.write('${timeStamp.inHours - timeStamp.inDays * Duration.hoursPerDay}h ');
    }
    if (timeStamp.inMinutes > 0) {
      buffer.write('${timeStamp.inMinutes - timeStamp.inHours * Duration.minutesPerHour}m ');
    }
    if (timeStamp.inSeconds > 0) {
      buffer.write('${timeStamp.inSeconds - timeStamp.inMinutes * Duration.secondsPerMinute}s ');
    }
    buffer.write('${timeStamp.inMilliseconds - timeStamp.inSeconds * Duration.millisecondsPerSecond}');
    final int microseconds = timeStamp.inMicroseconds - timeStamp.inMilliseconds * Duration.microsecondsPerMillisecond;
    if (microseconds > 0) {
      buffer.write('.${microseconds.toString().padLeft(3, "0")}');
    }
    buffer.write('ms');
  }
dart 复制代码
  // Calls the given [callback] with [timestamp] as argument.
  //
  // Wraps the callback in a try/catch and forwards any error to
  // [debugSchedulerExceptionHandler], if set. If not set, prints
  // the error.
  // 中文:使用[timestamp]作为参数调用给定的[callback]。
  //
  // 中文:将回调包装在try/catch中,并将任何错误转发给
  // 中文:[debugSchedulerExceptionHandler](如果设置)。如果未设置,则打印错误。
  @pragma('vm:notify-debugger-on-exception')
  void _invokeFrameCallback(FrameCallback callback, Duration timeStamp, [ StackTrace? callbackStack ]) {
    assert(_FrameCallbackEntry.debugCurrentCallbackStack == null);
    assert(() {
      _FrameCallbackEntry.debugCurrentCallbackStack = callbackStack;
      return true;
    }());
    try {
      callback(timeStamp);
    } catch (exception, exceptionStack) {
      FlutterError.reportError(FlutterErrorDetails(
        exception: exception,
        stack: exceptionStack,
        library: 'scheduler library',
        context: ErrorDescription('during a scheduler callback'),
        // 中文:在调度器回调期间
        informationCollector: (callbackStack == null) ? null : () {
          return <DiagnosticsNode>[
            DiagnosticsStackTrace(
              '\nThis exception was thrown in the context of a scheduler callback. '
              'When the scheduler callback was _registered_ (as opposed to when the '
              'exception was thrown), this was the stack',
              // 中文:\n这个异常是在调度器回调的上下文中抛出的。
              // 中文:当调度器回调被_注册_(而不是异常被抛出)时,这是堆栈
              callbackStack,
            ),
          ];
        },
      ));
    }
    assert(() {
      _FrameCallbackEntry.debugCurrentCallbackStack = null;
      return true;
    }());
  }
}

/// The default [SchedulingStrategy] for [SchedulerBinding.schedulingStrategy].
///
/// If there are any frame callbacks registered, only runs tasks with
/// a [Priority] of [Priority.animation] or higher. Otherwise, runs
/// all tasks.
/// 中文:[SchedulerBinding.schedulingStrategy]的默认[SchedulingStrategy]。
///
/// 中文:如果有任何帧回调注册,则只运行[Priority]为[Priority.animation]
/// 中文:或更高的任务。否则,运行所有任务。
bool defaultSchedulingStrategy({ required int priority, required SchedulerBinding scheduler }) {
  if (scheduler.transientCallbackCount > 0) {
    return priority >= Priority.animation.value;
  }
  return true;
}

这个类是 Flutter 框架的核心部分,负责管理帧调度、任务调度和时间处理等关键功能。

相关推荐
LawrenceLan9 小时前
Flutter 零基础入门(九):构造函数、命名构造函数与 this 关键字
开发语言·flutter·dart
一豆羹10 小时前
macOS 环境下 ADB 无线调试连接失败、Protocol Fault 及端口占用的深度排查
flutter
行者9610 小时前
OpenHarmony上Flutter粒子效果组件的深度适配与实践
flutter·交互·harmonyos·鸿蒙
行者9613 小时前
Flutter与OpenHarmony深度集成:数据导出组件的实战优化与性能提升
flutter·harmonyos·鸿蒙
小雨下雨的雨13 小时前
Flutter 框架跨平台鸿蒙开发 —— Row & Column 布局之轴线控制艺术
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨13 小时前
Flutter 框架跨平台鸿蒙开发 —— Center 控件之完美居中之道
flutter·ui·华为·harmonyos·鸿蒙
小雨下雨的雨14 小时前
Flutter 框架跨平台鸿蒙开发 —— Icon 控件之图标交互美学
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨14 小时前
Flutter 框架跨平台鸿蒙开发 —— Placeholder 控件之布局雏形美学
flutter·ui·华为·harmonyos·鸿蒙系统
行者9615 小时前
OpenHarmony Flutter弹出菜单组件深度实践:从基础到高级的完整指南
flutter·harmonyos·鸿蒙
前端不太难15 小时前
Flutter / RN / iOS,在长期维护下的性能差异本质
flutter·ios