Flutter笔记:关于SchedulerBinding

举报
jcLee95 发表于 2024/05/18 10:57:38 2024/05/18
【摘要】 在Flutter开发中WidgetsBinding更常见,一般不会直接使用SchedulerBinding。本文基于Flutter源码及其相关注释,记录关于SchedulerBinding相关内容。比较而言,WidgetsBinding主要关注应用的上层逻辑和状态,而SchedulerBinding主要关注底层的任务调度和执行。
Flutter笔记
关于SchedulerBinding

- 文章信息 -
Author: 李俊才 (jcLee95)
Visit me at CSDN: https://jclee95.blog.csdn.net
My WebSitehttp://thispage.tech/
Email: 291148484@163.com.
Shenzhen China
Address of this article:https://blog.csdn.net/qq_28550263/article/details/139018015
HuaWei:https://bbs.huaweicloud.cn/blogs/427627

【简介】:在Flutter开发中WidgetsFlutterBinding更常见,一般不会直接使用SchedulerBinding。实际上WidgetsFlutterBindingRenderdingFlutterBinding组合了SchedulerBinding等更多底层的Bing。本文基于Flutter源码及其相关注释,记录关于SchedulerBinding相关内容。比较而言,WidgetsBinding主要关注应用的上层逻辑和状态,而SchedulerBinding主要关注底层的任务调度和执行。

flutter-ljc



Flutter框架中,SchedulerBinding是一个非常重要的mixin,它为Flutter应用程序提供了调度帧(Frame)和任务(Task)的核心功能。SchedulerBindingFlutter引擎紧密配合,负责管理帧的生命周期,协调各种类型的回调函数,以及优化应用的性能。


SchedulerBindingFlutter框架中不可或缺的一部分,它为开发者提供了控制应用生命周期、优化性能的强大工具。SchedulerBindingFlutter框架中的的功能包括:

  1. 它是连接Flutter应用程序和Flutter引擎的桥梁,负责与引擎进行通信,接收引擎发出的帧事件(Frame events),并触发相应的回调函数。
  2. 它管理着Flutter应用的帧率(Frame rate),根据设备性能和应用需求,自动调整帧率以提供流畅的用户体验。
  3. 它提供了注册和调度各种类型回调函数的API,包括Transient frame callbacksPersistent frame callbacksPost-frame callbacks等,让开发者能够在适当的时机执行自己的逻辑。
  4. 它还负责管理任务队列,根据任务的优先级和当前的调度策略,合理地安排任务的执行顺序,避免应用出现卡顿或无响应的情况。

SchedulerBinding的主要职责可以归纳为以下几点:

  1. 帧调度(Frame scheduling):与Flutter引擎协作,接收并处理onBeginFrameonDrawFrame回调,触发帧的构建(build)和绘制(draw)过程。
  2. 回调管理(Callback management):提供注册和移除Transient frame callbacksPersistent frame callbacksPost-frame callbacks的方法,确保回调函数在正确的时机被调用。
  3. 任务调度(Task scheduling):管理一个优先级队列,根据任务的优先级和当前的调度策略(schedulingStrategy),合理安排任务的执行顺序。
  4. 帧率控制(Frame rate control):根据设备性能和应用需求,动态调整帧率(timeDilation),以平衡流畅度和电池消耗。
  5. 生命周期管理(Lifecycle management):监听应用的生命周期事件(AppLifecycleState),如应用进入前台或后台,并触发相应的回调函数。
  6. 时间戳处理(Timestamp handling):提供currentFrameTimeStampcurrentSystemFrameTimeStamp属性,供开发者获取当前帧的时间戳,同时还支持添加自定义的时间戳回调(TimestampCallback)。

通过对这些职责的有效履行,SchedulerBinding确保了Flutter应用能够高效、流畅地运行,并为开发者提供了灵活的控制手段。在后续的章节中,我们将深入探讨SchedulerBinding的关键概念和使用方法。

需要指出,SchedulerBinding是一种非常低层次、高风险的操作,只应该在一些非常特殊和罕见的场景下使用。在绝大多数情况下,我们都应该使用Flutter提供的高层API、组件和插件,以保证应用的性能、稳定性和可维护性。只有在我们确实需要实现一些Flutter框架不支持的、非常定制化的功能时,才应该考虑直接使用SchedulerBinding,并且要非常谨慎地进行设计、实现和测试。


要理解SchedulerBinding的工作原理和使用方法,首先需要了解一些关键概念。本节将介绍FrameFrame callbacks以及SchedulerBinding中的几种callback类型和调度阶段。


Flutter中,Frame表示一次完整的UI渲染过程,包括构建Widget树、布局、绘制等步骤。Frame的生成由Flutter引擎驱动,通常以每秒60次的频率进行。

Frame callbacks则是在每一帧的特定时间点被调用的回调函数。通过Frame callbacks,我们可以在一帧的不同阶段执行自定义的逻辑,例如启动动画、更新状态等。SchedulerBinding提供了注册和管理Frame callbacks的方法。


Transient frame callbacks是一次性的帧回调,只在注册后的下一帧被调用一次。可以通过SchedulerBinding.scheduleFrameCallback方法注册Transient frame callback

SchedulerBinding.instance.scheduleFrameCallback((_) {
  // 在下一帧执行一些操作
  print('Transient frame callback executed');
});

Transient callbacks适用于只需要执行一次的场景,例如触发一个动画。


Transient frame callbacks不同,Persistent frame callbacks会在每一帧都被调用,直到被移除为止。可以通过SchedulerBinding.addPersistentFrameCallback方法注册:

void onFrame(Duration timeStamp) {
  // 在每一帧执行一些操作
  print('Persistent frame callback executed');
}

SchedulerBinding.instance.addPersistentFrameCallback(onFrame);

要移除一个Persistent frame callback,可以调用SchedulerBinding.removePersistentFrameCallback方法:

SchedulerBinding.instance.removePersistentFrameCallback(onFrame);

Persistent callbacks通常用于需要在每一帧都执行的场景,例如实时更新UI、动画等。


Post-frame callbacks会在当前帧的所有Persistent callbacks执行完毕后、下一帧开始前被调用。可以通过SchedulerBinding.addPostFrameCallback方法注册:

SchedulerBinding.instance.addPostFrameCallback((_) {
  // 在当前帧结束后执行一些操作  
  print('Post-frame callback executed');
});

Post-frame callbacks适用于需要在当前帧的最后执行的场景,例如在布局或绘制完成后更新状态。


SchedulerBinding将一帧划分为几个阶段,不同类型的callbacks在不同阶段执行:

  1. Idle(空闲): 表示当前没有正在处理的帧。
  2. Transient callbacks(瞬时回调): 执行Transient frame callbacks
  3. Midframe microtasks(帧中微任务): 执行Transient callbacks产生的微任务。
  4. Persistent callbacks(持久回调): 执行Persistent frame callbacks
  5. Post-frame callbacks(后帧回调): 执行Post-frame callbacks

了解这些阶段有助于了解这些阶段有助于我们选择合适的callback类型,并避免在错误的阶段执行耗时操作而影响UI性能。例如,在Persistent callbacks阶段执行复杂的计算或I/O操作可能会导致掉帧。

通过SchedulerBinding.schedulerPhase属性可以获取当前的调度阶段:

SchedulerPhase phase = SchedulerBinding.instance.schedulerPhase;
if (phase == SchedulerPhase.persistentCallbacks) {
  // 在持久回调阶段执行一些操作
} else if (phase == SchedulerPhase.idle) {
  // 在空闲阶段执行一些操作
}

理解FrameFrame callbacks以及SchedulerBinding的调度阶段,是高效使用SchedulerBinding的基础。在实际应用中,我们应该根据具体的需求选择合适的callback类型和调用时机,避免不必要的性能开销,从而构建流畅、响应迅速的Flutter应用。



Transient frame callbacks 是一次性的帧回调,会在下一帧开始时被调用,调用后就会自动移除。我们可以通过 SchedulerBinding.instance.scheduleFrameCallback 方法来注册一个 Transient frame callback

int id = SchedulerBinding.instance.scheduleFrameCallback((_) {
  // 在下一帧开始时执行一些操作
  ...
}, rescheduling: false);

其中 rescheduling 参数表示是否在回调执行完后自动重新注册,一般不需要。

如果要提前移除一个 Transient frame callback,可以使用 SchedulerBinding.instance.cancelFrameCallbackWithId 方法:

SchedulerBinding.instance.cancelFrameCallbackWithId(id);

Persistent frame callbacks 是持久的帧回调,一旦注册后,每一帧都会被调用,直到主动移除。我们可以通过 SchedulerBinding.instance.addPersistentFrameCallback 方法来注册:

void callback(Duration timeStamp) {
  // 在每一帧执行一些操作
  ...
}
SchedulerBinding.instance.addPersistentFrameCallback(callback);

如果要移除一个 Persistent frame callback,可以使用 SchedulerBinding.instance.removePersistentFrameCallback 方法:

SchedulerBinding.instance.removePersistentFrameCallback(callback);

Post-frame callbacks 是一次性的后帧回调,会在当前帧绘制完成后被调用。我们可以通过 SchedulerBinding.instance.addPostFrameCallback 方法来注册:

SchedulerBinding.instance.addPostFrameCallback((_) {
  // 在当前帧绘制完成后执行一些操作  
  ...
});

Post-frame callbacks 不需要主动移除,在回调函数执行完后会自动移除。


除了帧回调,SchedulerBinding 还提供了调度和执行任务的能力。我们可以通过 SchedulerBinding.instance.scheduleTask 方法来调度一个异步任务:

SchedulerBinding.instance.scheduleTask(() async {
  // 执行一些异步任务
  ...  
}, Priority.animation);

其中第二个参数是任务的优先级,优先级越高的任务会越早执行。

SchedulerBinding 内部有一个任务队列,任务会在每一帧的空闲时间去执行。如果某一帧有动画回调,则优先级低于 Priority.animation 的任务会暂停执行,让出时间给动画,避免动画卡顿。

以上就是 SchedulerBinding 的一些主要功能和用法,它为 Flutter 应用提供了灵活的调度能力。合理利用 SchedulerBinding,可以实现各种自定义的动画效果、与外部数据源同步、优化性能等功能,是 Flutter 开发中非常重要的一个类。


Flutter默认的帧率是60fps,但有时我们可能需要降低帧率以节省电量,或者提高帧率以获得更流畅的动画效果。SchedulerBinding提供了timeDilation属性来控制帧率:

// 降低帧率到30fps
SchedulerBinding.instance.timeDilation = 2.0;

// 提高帧率到120fps
SchedulerBinding.instance.timeDilation = 0.5;

timeDilation的默认值为1.0,表示60fps。设置为2.0时,每一帧的时间会变为原来的2倍,所以帧率降为30fps。设置为0.5时,每一帧的时间会变为原来的一半,所以帧率提高为120fps

注意,提高帧率会增加CPUGPU的负载,可能会导致耗电增加和发热加剧,所以一般只在必要时短暂地提高帧


SchedulerBinding提供了一些属性和方法来监听应用的生命周期事件:

  • lifecycleState属性:表示应用当前的生命周期状态,是一个AppLifecycleState枚举值。
  • addObserverremoveObserver方法:可以添加和移除SchedulerObserver,在应用生命周期状态发生变化时会收到通知。

例如:

class MySchedulerObserver implements SchedulerObserver {
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print('App lifecycle state changed to $state');
  }
}

MySchedulerObserver observer = MySchedulerObserver();
SchedulerBinding.instance.addObserver(observer);

上面的代码添加了一个SchedulerObserver,它会在应用生命周期状态发生变化时打印出新的状态。


SchedulerBinding允许我们添加时间戳回调函数,在每一帧开始时,Flutter引擎会将该帧的时间戳信息传递给这些回调函数。这对于实现一些需要精确计时的功能非常有用,比如音视频同步、数据采集等。

可以通过SchedulerBinding.instance.addTimingsCallback方法添加时间戳回调:

void callback(List<FrameTiming> timings) {
  // 处理时间戳信息
  ...
}
SchedulerBinding.instance.addTimingsCallback(callback);
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。