flutter scheduler 机制

flutter 中的 WidgetsFlutterBinding 集成了 GestureBinding、ServicesBinding、SchedulerBinding、PaintingBinding、SemanticsBinding、RendererBinding、WidgetsBinding 等 7 种 Binding,它们都有自己在功能上的划分,其中,SchedulerBinding 主要负责的是 flutter 中视图刷新、延迟回调相关的,有点类似于 android 中的 Choreographer 的功能,事实上 SchedulerBinding 的一部分功能也是基于 Choreographer 完成的。

void initInstances() {
  super.initInstances();
  _instance = this;
  window.onBeginFrame = _handleBeginFrame;
  window.onDrawFrame = _handleDrawFrame;
  SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
  readInitialLifecycleStateFromNativeWindow();
}

在 SchedulerBinding 的 initInstances 中,向 window 注册了 onBeginFrame 和 onDrawFrame 两个函数,然后给 SystemChannels.lifecycle 注册了一个接收器,用于接收生命周期相关的消息,这个主要是用于控制 flutter 是否需要继续刷新视图,最后的 readInitialLifecycleStateFromNativeWindow 能够从 native 层读取到当前的生命周期状态,最为 flutter 的初始状态。

SchedulerBinding 本身大致包含两部分功能,第一步部分为刷新视图相关的,当需要刷新视图时,就会调用 scheduleFrame 向 native 层发起一个刷新视图的请求,然后当时机到达时,native 通过调用 onBegineFrame 和 onDrawFrame 这两个函数,SchedulerBinding 便会在这两个回调用完成刷新视图所需的操作,比如更新 widgets、执行动画、直到最后视图的渲染,以上操作都完成后,SchedulerBinding 便会再调用 scheduleFrame 发起刷新请求,等待下一次刷新时机的到来。同时 SchedulerBinding 也支持在视图刷新的间隙中执行一些其他操作,可以通过 scheduleTask 传入待执行的 task ,SchedulerBinding 会寻找合适的时机去执行,但是本质上这些 task 还是运行在主线程中,与 Future 类似,任务过重会导致 UI 卡顿,只不过这里的执行更严格,增加了对 task 优先级的区分。

void runApp(Widget app) {
  WidgetsFlutterBinding.ensureInitialized()
    ..attachRootWidget(app)
    ..scheduleWarmUpFrame();
}

如上,在 flutter 应用启动的最后阶段,调用了 scheduleWarmUpFrame,这个函数就是启动 SchedulerBinding 进行第一次试图更新的,在它的内部依次会调用 handleBeginFrame、handleDrawFrame 和 scheduleFrame 三个函数,完成第一次渲染的工作。

handleBegineFrame

void handleBeginFrame(Duration rawTimeStamp) {
  Timeline.startSync('Frame', arguments: timelineWhitelistArguments);
  _firstRawTimeStampInEpoch ??= rawTimeStamp;
  _currentFrameTimeStamp = _adjustForEpoch(rawTimeStamp ?? _lastRawTimeStamp);
  if (rawTimeStamp != null)
    _lastRawTimeStamp = rawTimeStamp;
  
  assert(schedulerPhase == SchedulerPhase.idle);
  _hasScheduledFrame = false;
  try {
    // TRANSIENT FRAME CALLBACKS
    Timeline.startSync('Animate', arguments: timelineWhitelistArguments);
    _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;
  }
}

从 handleBeginFrame 的实现来看,这里只是完成了所有 transientCallbacks 回调,这个回调通过 scheduleFrameCallback 函数添加,从这个函数的使用上看,在 Ticker.scheduleTick 中,它向 transientCallbacks 中添加了 tick 回调函数,具体使用这里不阐述,而 Ticker 主要的功能,就是被 AnimationController 使用,也就是动画,所以,transientCallbacks 主要的功能可以看作为用于动画的实现。

那么也就可以理解,为什么 transientCallbacks 会在 onDrawFrame 之前执行了,在渲染之前先更新各 widgets ,然后再将 widgets 渲染。

handleDrawFrame

void handleDrawFrame() {
  assert(_schedulerPhase == SchedulerPhase.midFrameMicrotasks);
  Timeline.finishSync(); // end the "Animate" phase
  try {
    // PERSISTENT FRAME CALLBACKS
    _schedulerPhase = SchedulerPhase.persistentCallbacks;
    for (FrameCallback callback in _persistentCallbacks)
      _invokeFrameCallback(callback, _currentFrameTimeStamp);
    // POST-FRAME CALLBACKS
    _schedulerPhase = SchedulerPhase.postFrameCallbacks;
    final List<FrameCallback> localPostFrameCallbacks =
        List<FrameCallback>.from(_postFrameCallbacks);
    _postFrameCallbacks.clear();
    for (FrameCallback callback in localPostFrameCallbacks)
      _invokeFrameCallback(callback, _currentFrameTimeStamp);
  } finally {
    _schedulerPhase = SchedulerPhase.idle;
    Timeline.finishSync(); // end the Frame
    
    _currentFrameTimeStamp = null;
  }
}

在 handleDrawFrame 中执行了两种回调函数,persistentCallbacks 和 postFrameCallbacks。

persistentCallbacks

persistentCallbacks 也就是固定的回调,不会每次执行之后被清空,而这个回调在 flutter 中目前只有两个使用场景,一个是在 WidgetInspectorService 中用于统计渲染过程的耗时,另一个就是在 RenderBinding 中,添加了 _handlePersistentFrameCallback 回调,这个函数被用于在 RenderBinding 中开启画面渲染。

所以 persistentCallbacks 可以看作是 flutter 中真正的渲染过程,这个回调执行完了之后,用户看到的视图就会刷新。

postFrameCallbacks

postFrameCallbacks 在渲染之后调用,可用于执行一些清理操作或者是继续请求刷新视图等。比如在 WidgetInspectorService,通过添加 postFrameCallbacks 统计渲染的耗时。

scheduleFrame

scheduleFrame 中调用了 window.scheduleFrame,内部会向 native 请求回调,它对应的 engine 中的函数为:

void ScheduleFrame(Dart_NativeArguments args) {
  UIDartState::Current()->window()->client()->ScheduleFrame();
}

这里传给了 RuntimeController,然后继续调用 Engine、Animator 中相关的函数,在 Animator 中的实现如下:

void Animator::RequestFrame(bool regenerate_layer_tree) {
  if (regenerate_layer_tree) {
    regenerate_layer_tree_ = true;
  }
  if (paused_ && !dimension_change_pending_) {
    return;
  }

  if (!pending_frame_semaphore_.TryWait()) {
    // Multiple calls to Animator::RequestFrame will still result in a
    // single request to the VsyncWaiter.
    return;
  }

  // The AwaitVSync is going to call us back at the next VSync. However, we want
  // to be reasonably certain that the UI thread is not in the middle of a
  // particularly expensive callout. We post the AwaitVSync to run right after
  // an idle. This does NOT provide a guarantee that the UI thread has not
  // started an expensive operation right after posting this message however.
  // To support that, we need edge triggered wakes on VSync.

  task_runners_.GetUITaskRunner()->PostTask([self = weak_factory_.GetWeakPtr(),
                                             frame_number = frame_number_]() {
    if (!self.get()) {
      return;
    }
    TRACE_EVENT_ASYNC_BEGIN0("flutter", "Frame Request Pending", frame_number);
    self->AwaitVSync();
  });
  frame_scheduled_ = true;
}

void Animator::AwaitVSync() {
  waiter_->AsyncWaitForVsync(
      [self = weak_factory_.GetWeakPtr()](fml::TimePoint frame_start_time,
                                          fml::TimePoint frame_target_time) {
        if (self) {
          if (self->CanReuseLastLayerTree()) {
            self->DrawLastLayerTree();
          } else {
            self->BeginFrame(frame_start_time, frame_target_time);
          }
        }
      });

  delegate_.OnAnimatorNotifyIdle(dart_frame_deadline_);
}

在这里,Animator 先是切换到 UI 线程,再调用的 AwaitVSync ,AwaitVSync 中有三步工作,首先声明了一个 callback ,在 callback 里可以看到,会执行 BeginFrame(然后一步步会调用到 flutter 中的 onBegineFrame),然后调用 waiter 的 AsyncWaitForVsync,最后调用 Shell 的 OnAnimatorNotifyIdle,向其通知现在是空闲时间,可以在这段时间中执行一些其他任务,比如 CG 等。

waiter 对应的类是 VsyncWaiter,VsyncWaiter 是一个基类,在不同的平台会使用不同的子类,比如 VsyncWaiterAndroid、VsyncWaiterIOS,以 android 为例,

void VsyncWaiterAndroid::AwaitVSync() {
  auto* weak_this = new std::weak_ptr<VsyncWaiter>(shared_from_this());
  jlong java_baton = reinterpret_cast<jlong>(weak_this);

  task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() {
    JNIEnv* env = fml::jni::AttachCurrentThread();
    env->CallStaticVoidMethod(g_vsync_waiter_class->obj(),     //
                              g_async_wait_for_vsync_method_,  //
                              java_baton                       //
    );
  });
}

会先切换到 Platform 线程,再通过 jni 调用 FlutterJNI.asyncWaitForVsync 方法。

private static void asyncWaitForVsync(final long cookie) {
  if (asyncWaitForVsyncDelegate != null) {
    asyncWaitForVsyncDelegate.asyncWaitForVsync(cookie);
  } else {
    throw new IllegalStateException(
        "An AsyncWaitForVsyncDelegate must be registered with FlutterJNI before asyncWaitForVsync() is invoked.");
  }
}

private final FlutterJNI.AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate =
    new FlutterJNI.AsyncWaitForVsyncDelegate() {
      @Override
      public void asyncWaitForVsync(long cookie) {
        Choreographer.getInstance()
            .postFrameCallback(
                new Choreographer.FrameCallback() {
                  @Override
                  public void doFrame(long frameTimeNanos) {
                    float fps = windowManager.getDefaultDisplay().getRefreshRate();
                    long refreshPeriodNanos = (long) (1000000000.0 / fps);
                    FlutterJNI.nativeOnVsync(
                        frameTimeNanos, frameTimeNanos + refreshPeriodNanos, cookie);
                  }
                });
      }
    };

如上,asyncWaitForVsyncDelegate 的 asyncWaitForVsync 方法内部,是依赖于 Choreographer 实现的,向 Choreographer 中添加回调,在回调中调用 FlutterJNI.nativeOnVsync 将事件传递到 engine 中。了解 android 开发的知道,Choreographer 在 android 中就是用于生成帧的,之于 android 就相当于 SchedulerBinding 之于 flutter,只不过 SchedulerBinding 依赖于 Choreographer,Choreographer 依赖的是系统实现。

当 doFrame 方法被调用时,新的一帧开始,FlutterJNI.nativeOnVsync 在 engine 中对应的函数为 VsyncWaiterAndroid::OnNativeVsync,这个函数的三个参数的意义分别是:当前的时间、预计的下一帧开始的时间和 VsyncWaiterAndroid 的指针(cookie),后面在 jni 中还需要根据它找到对应的 VsyncWaiterAndroid 对象。

OnNativeVsync 将两个时间进行转换之后再调用了 ConsumePendingCallback,然后在这里取出 VsyncWaiterAndroid 对象,调用其 FireCallback。

FireCallback 的实现位于 VsyncWaiter 中,

void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
                               fml::TimePoint frame_target_time) {
  Callback callback;
  fml::closure secondary_callback;

  {
    std::scoped_lock lock(callback_mutex_);
    callback = std::move(callback_);
    secondary_callback = std::move(secondary_callback_);
  }

  if (!callback && !secondary_callback) {
    // This means that the vsync waiter implementation fired a callback for a
    // request we did not make. This is a paranoid check but we still want to
    // make sure we catch misbehaving vsync implementations.
    TRACE_EVENT_INSTANT0("flutter", "MismatchedFrameCallback");
    return;
  }

  if (callback) {
    auto flow_identifier = fml::tracing::TraceNonce();

    // The base trace ensures that flows have a root to begin from if one does
    // not exist. The trace viewer will ignore traces that have no base event
    // trace. While all our message loops insert a base trace trace
    // (MessageLoop::RunExpiredTasks), embedders may not.
    TRACE_EVENT0("flutter", "VsyncFireCallback");

    TRACE_FLOW_BEGIN("flutter", kVsyncFlowName, flow_identifier);

    task_runners_.GetUITaskRunner()->PostTaskForTime(
        [callback, flow_identifier, frame_start_time, frame_target_time]() {
          FML_TRACE_EVENT("flutter", kVsyncTraceName, "StartTime",
                          frame_start_time, "TargetTime", frame_target_time);
          fml::tracing::TraceEventAsyncComplete(
              "flutter", "VsyncSchedulingOverhead", fml::TimePoint::Now(),
              frame_start_time);
          callback(frame_start_time, frame_target_time);
          TRACE_FLOW_END("flutter", kVsyncFlowName, flow_identifier);
        },
        frame_start_time);
  }

  if (secondary_callback) {
    task_runners_.GetUITaskRunner()->PostTaskForTime(
        std::move(secondary_callback), frame_start_time);
  }
}

这个函数主要的就是切换到 UI 线程执行了 callback,也就是 AsyncWaitForVsync 中传进来、在 AwaitVSync 中声明的:

void Animator::AwaitVSync() {
  waiter_->AsyncWaitForVsync(
      [self = weak_factory_.GetWeakPtr()](fml::TimePoint frame_start_time,
                                          fml::TimePoint frame_target_time) {
        if (self) {
          if (self->CanReuseLastLayerTree()) {
            self->DrawLastLayerTree();
          } else {
            self->BeginFrame(frame_start_time, frame_target_time);
          }
        }
      });

  delegate_.OnAnimatorNotifyIdle(dart_frame_deadline_);
}

从这里开始,就需要开始进行新一帧的绘制(如果不需要重新绘制的话,会直接重用上一次的),调用 BeginFrame。

void Animator::BeginFrame(fml::TimePoint frame_start_time,
                          fml::TimePoint frame_target_time) {
  TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending", frame_number_++);

  TRACE_EVENT0("flutter", "Animator::BeginFrame");
  while (!trace_flow_ids_.empty()) {
    uint64_t trace_flow_id = trace_flow_ids_.front();
    TRACE_FLOW_END("flutter", "PointerEvent", trace_flow_id);
    trace_flow_ids_.pop_front();
  }

  frame_scheduled_ = false;
  notify_idle_task_id_++;
  regenerate_layer_tree_ = false;
  pending_frame_semaphore_.Signal();

  if (!producer_continuation_) {
    // We may already have a valid pipeline continuation in case a previous
    // begin frame did not result in an Animation::Render. Simply reuse that
    // instead of asking the pipeline for a fresh continuation.
    producer_continuation_ = layer_tree_pipeline_->Produce();

    if (!producer_continuation_) {
      // If we still don't have valid continuation, the pipeline is currently
      // full because the consumer is being too slow. Try again at the next
      // frame interval.
      RequestFrame();
      return;
    }
  }

  // We have acquired a valid continuation from the pipeline and are ready
  // to service potential frame.
  FML_DCHECK(producer_continuation_);

  last_begin_frame_time_ = frame_start_time;
  dart_frame_deadline_ = FxlToDartOrEarlier(frame_target_time);
  {
    TRACE_EVENT2("flutter", "Framework Workload", "mode", "basic", "frame",
                 FrameParity());
    delegate_.OnAnimatorBeginFrame(frame_target_time);
  }

  if (!frame_scheduled_) {
    // Under certain workloads (such as our parent view resizing us, which is
    // communicated to us by repeat viewport metrics events), we won't
    // actually have a frame scheduled yet, despite the fact that we *will* be
    // producing a frame next vsync (it will be scheduled once we receive the
    // viewport event).  Because of this, we hold off on calling
    // |OnAnimatorNotifyIdle| for a little bit, as that could cause garbage
    // collection to trigger at a highly undesirable time.
    task_runners_.GetUITaskRunner()->PostDelayedTask(
        [self = weak_factory_.GetWeakPtr(),
         notify_idle_task_id = notify_idle_task_id_]() {
          if (!self.get()) {
            return;
          }
          // If our (this task's) task id is the same as the current one
          // (meaning there were no follow up frames to the |BeginFrame| call
          // that posted this task) and no frame is currently scheduled, then
          // assume that we are idle, and notify the engine of this.
          if (notify_idle_task_id == self->notify_idle_task_id_ &&
              !self->frame_scheduled_) {
            TRACE_EVENT0("flutter", "BeginFrame idle callback");
            self->delegate_.OnAnimatorNotifyIdle(Dart_TimelineGetMicros() +
                                                 100000);
          }
        },
        kNotifyIdleTaskWaitTime);
  }
}

第一步判断是否可以开始新一帧的渲染,如果 ProducerContinuation 为空,就调用 layer_tree_pipeline_->Produce 获取,如果还是没有获取到,就会直接跳过本次渲染,直接请求下一帧(这就会造成用户看起来的卡顿)。第二步就是调用 delegate_.OnAnimatorBeginFrame 将其继续往 flutter 中传递(后续的 flutter 中的渲染都在这个函数中,没有切换线程)。第三步是判断在执行完了本帧的渲染之后,是否已经进行了下一帧的请求,也就是上面 ScheduleFrame 的过程,如果没有的话,就调用 delegate_.OnAnimatorNotifyIdle,跟在 AwaitVSync 调用这个函数一样,可以用户执行一些 CG 操作,如果已经执行了 ScheduleFrame 的话,那么也应该会直接在 AwaitVSync 中调用这个函数,所以,从这个角度来看,无论是哪种方式,都会调用 delegate_.OnAnimatorNotifyIdle。

delegate_.OnAnimatorBeginFrame 后面会经过 Shell、Engine、RuntimeController、Window,最后在 Window.BegineFrame 中,依次调用了 flutter 中的 _beginFrame 和 _drawFrame 函数。从这里也可以看出,beginFrame 和 drawFrame 两个函数是先后调用的,与 flutter 中的 scheduleWarmUpFrame 调用顺序保持一致。

上面两个函数会调用 window.onBeginFrame 和 window.onDrawFrame,也就是在 SchedulerBinding.initInstances 中设置的 _handleBeginFrame 和 _handleDrawFrame,

void _handleBeginFrame(Duration rawTimeStamp) {
  if (_warmUpFrame) {
    assert(!_ignoreNextEngineDrawFrame);
    _ignoreNextEngineDrawFrame = true;
    return;
  }
  handleBeginFrame(rawTimeStamp);
}

void _handleDrawFrame() {
  if (_ignoreNextEngineDrawFrame) {
    _ignoreNextEngineDrawFrame = false;
    return;
  }
  handleDrawFrame();
}

最后会调用到 handleBeginFrame 和 handleDrawFrame。

_handleLifecycleMessage

initInstances 中的另一个任务就是注册 _handleLifecycleMessage 处理生命周期相关的消息。

void handleAppLifecycleStateChanged(AppLifecycleState state) {
  assert(state != null);
  _lifecycleState = state;
  switch (state) {
    case AppLifecycleState.resumed:
    case AppLifecycleState.inactive:
      _setFramesEnabledState(true);
      break;
    case AppLifecycleState.paused:
    case AppLifecycleState.suspending:
      _setFramesEnabledState(false);
      break;
  }
}

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

由以上可以知道,当 flutter 依赖的 Activity(in android for example)处于活跃状态时,_framesEnabled 为真, 而 _framesEnabled 的用处,主要就是在 scheduleFrame 中:

void scheduleFrame() {
  if (_hasScheduledFrame || !_framesEnabled)
    return;
  assert(() {
    if (debugPrintScheduleFrameStacks)
      debugPrintStack(label: 'scheduleFrame() called. Current phase is $schedulerPhase.');
    return true;
  }());
  window.scheduleFrame();
  _hasScheduledFrame = true;
}

只有当其为真时,才会执行到 window.scheduleFrame,从而停止更新视图,而当 Activity 重新变为活跃状态时,也就是 _setFramesEnabledState 参数为真时,可以看到就会调用 scheduleFrame 重新开始刷新视图。

scheduleTask

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;
}

使用 scheduleTask 运行了 task 除了要提供 task 本身之外,还要提供一个 Priority,用于判断 task 是否会被执行以及何时被执行。该函数参数会被封装成 _TaskEntry,存放在 _taskQueue 中,_taskQueue 是一个 HeapPriorityQueue 对象,它内部会根据 task 的 priority 进行排序,保证每次取出的都是当前队列中优先级最高的一个。

接下来可以有三种情况:

  1. 该 task 是第一个待执行,且没有上锁(上锁期间不能执行 task),执行 _ensureEventLoopCallback
  2. 该 task 是第一个待执行,但是上锁了,就直接结束,不过当锁解除的时候,也就是在 SchedulerBinding 的 unlocked 中,如果有待执行 task,还是会执行 _ensureEventLoopCallback
  3. 该 task 不是第一个待执行,那么直接结束,由此可以推测,一旦开始执行 task,直到 _taskQueue 为空或者上锁了,应该会循环之行 task

再看 _ensureEventLoopCallback 的实现,

void _ensureEventLoopCallback() {
  assert(!locked);
  assert(_taskQueue.isNotEmpty);
  if (_hasRequestedAnEventLoopCallback)
    return;
  _hasRequestedAnEventLoopCallback = true;
  Timer.run(_runTasks);
}

void _runTasks() {
  _hasRequestedAnEventLoopCallback = false;
  if (handleEventLoopCallback())
    _ensureEventLoopCallback(); // runs next task when there's time
}

_hasRequestedAnEventLoopCallback 用于防止多次进入,Timer.run 将会构建一个同步多线程回调 _runTasks,一般在线程空闲时执行,比如说在向 native 层请求了下一帧,但是还没有被回调之前。而在 _runTasks 中,

handleEventLoopCallback 用于处理一个 task,完了之后再调用 _ensureEventLoopCallback 循环执行一个新的 task,由此可见,_ensureEventLoopCallback 确实是一个循环执行的过程。

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 : () sync* {
          yield 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',
            callbackStack,
          );
        },
      ));
    }
    return _taskQueue.isNotEmpty;
  }
  return false;
}

首先还是一个状态判断,然后从 _taskQueue 取出一个 task,再进行是否可执行的判断,默认的 schedulingStrategy 实现如下:

bool defaultSchedulingStrategy({ int priority, SchedulerBinding scheduler }) {
  if (scheduler.transientCallbackCount > 0)
    return priority >= Priority.animation.value;
  return true;
}

这也正是注释里所说的,当有动画在执行时,只有优先级不小于 Priority.animation 的才能被执行。那么如果这里判断过不去,就直接返回 false 了。如果可以执行,就调用 task.run 执行,完了返回 _taskQueue 是否为空。

当 handleEventLoopCallback 执行完了之后,_runTasks 会根据它的返回值决定是否接着调用 _ensureEventLoopCallback。返回值有两种,返回真的情况就是上一个 task 执行了,并且 _taskQueue 中还有余量,返回 false 有两种情况,一种是状态判断没过去(_taskQueue 已经空了,或者上锁了),另一种就是优先级判断没过去,取出的是当前队列中优先级最高的,如果这个最高的都判断过不去,可以认为队列中剩余的 task 都是不能被执行的,只能等动画执行完了,但是目前好像并没有发现有在动画执行完的时候再启动这个循环(启动循环的方式只有两种,解锁和添加新的 task)。

总结

从以上来看,SchedulerBinding 的功能有两个,一是用于确定视图渲染的时间,在 flutter 应用运行的过程中,可以通过 setState 等方式请求刷新视图,此时 SchedulerBinding 接收到请求之后会再向 native 层添加回调,由 native 确定何时去执行视图刷新,同时 SchedulerBinding 还支持 flutter 中其他组件添加一些与帧渲染相关的回调,比如动画需要在渲染 widgets 之前更新 widgets 的内容等。另一方面,SchedulerBinding 还支持在帧渲染的间隙执行一些其他任务,这些任务需要只能在非渲染阶段执行,且受到优先级的限制,为的是能够使 UI 更流畅,如果要保证任务及时、更快地执行,可以使用 Future(在非渲染阶段执行,但是没有优先级限制)、Isolate(开辟新线程,不受 UI 线程影响) 等方式。