从源码分析Flutter 渲染

1,194 阅读4分钟

Flutter渲染过程的简介

使用Flutter开发有一段时间了,对Flutter的Framework层和Engine层有点模糊不清晰,趁着五一的假期,自己做个梳理;主要是想弄明白在Widget中使用setState后,Framework层和Engine层是怎么交互,从而让UI刷新的。

Flutter的渲染框架分为两层:

1)Framework层,负责渲染过程中的build、layout、paint、生成layer等环节;

2)Engine层,负责把Framwork层生成的layer组合生成纹理,然后通过OpenGL提交给GPU进行渲染;

Flutter的渲染过程可以大概分为下面几步:

1)Framework在setState后,调用接口通知Engine有UI需要更新;

2)Engine在下一个Vsync信号到达后,调用接口通知Framework层进行渲染;

3)Framework进行animations、build、layout、compositing、paint,生成layer提交给Engine层;

4)Engine层会把Layer进行组合生成纹理,通过OpenGL提交给GPU进行渲染;

一定要对上述的过程有个认识,否则看下面的代码会有点晕;大家可以看看参考一中的文章,写的很清晰。


Flutter渲染过程的源码分析

Framework和Engine之间的接口(胶水层)

sky_engine/lib/ui/window.dart 

Class Window{//Framework和Engine之间的交互接口;
    ...
    
    //Framework通过该接口通知Engine有UI需要更新,然后Engine会在Vsync信号到来后,调用下面的onBeginFrame和onDrawFrame
    void scheduleFrame() native 'Window_scheduleFrame';
    
    //Framework通过该接口将Layer信息交给Engine,Engine会在下一个Vsync来后将信息交给GPU进行渲染;
    void render(Scene scene) native 'Window_render';
    
    //当Engine收到Vsync信号后,调用onBeginFrame和onDrawFrame通知Framework进行绘制
    VoidCallback get onDrawFrame => _onDrawFrame;
    VoidCallback _onDrawFrame;
    Zone _onDrawFrameZone;
    set onDrawFrame(VoidCallback callback) {
        _onDrawFrame = callback;
        _onDrawFrameZone = Zone.current;
    }
    FrameCallback get onBeginFrame => _onBeginFrame;
    FrameCallback _onBeginFrame;
    Zone _onBeginFrameZone;
    set onBeginFrame(FrameCallback callback) {
        _onBeginFrame = callback;
        _onBeginFrameZone = Zone.current;
    }
    ....
}

从runApp开始

上述Window中的接口关联到Framework层,就是在runApp函数中通过WidgetsFlutterBinding设置上的;

flutter/lib/src/widgets/binding.dart

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

//注意这里的关键字with,这是dart的一种复用逻辑的方法
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
  static WidgetsBinding ensureInitialized() {
    if (WidgetsBinding.instance == null)
      WidgetsFlutterBinding();
    return WidgetsBinding.instance;
  }
}

各个binding的具体解释可以看参考二的文章;

关于Mixin的理解可以看参考三的文章;

BindingBase

flutter/lib/src/foundation/binding.dart

abstract class BindingBase {
    BindingBase() {
        developer.Timeline.startSync('Framework initialization');
    
        assert(!_debugInitialized);
        initInstances();
        assert(_debugInitialized);
    
        assert(!_debugServiceExtensionsRegistered);
        initServiceExtensions();
        assert(_debugServiceExtensionsRegistered);
    
        developer.postEvent('Flutter.FrameworkInitialization', {});
    
        developer.Timeline.finishSync();
      }
      
      ui.Window get window => ui.window;//关联Window
}

SchedulerBinding

flutter/lib/src/scheduler/binding.dart,提供了window.onBeginFrame和window.onDrawFrame回调,监听刷新事件,绑定Framework绘制调度子系统。

mixin SchedulerBinding on BindingBase, ServicesBinding {
  @override
  void initInstances() {
      ...
  }
  void ensureVisualUpdate() {//有element rebuild的时候会调用到这里
    switch (schedulerPhase) {
      case SchedulerPhase.idle:
      case SchedulerPhase.postFrameCallbacks:
        scheduleFrame();
        return;
      case SchedulerPhase.transientCallbacks:
      case SchedulerPhase.midFrameMicrotasks:
      case SchedulerPhase.persistentCallbacks:
        return;
    }
  }
  void scheduleFrame() {
    ...  
    ensureFrameCallbacksRegistered();
    window.scheduleFrame();//通知Engine有UI需要更新
    _hasScheduledFrame = true;
  }
  @protected
  void ensureFrameCallbacksRegistered() {
    //设置Engine在Vsync信号来的时候通知framework进行渲染的接口
    window.onBeginFrame ??= _handleBeginFrame;
    window.onDrawFrame ??= _handleDrawFrame;
  }
  void addPersistentFrameCallback(FrameCallback callback) {
    _persistentCallbacks.add(callback);
  }
  void _handleBeginFrame(Duration rawTimeStamp) {
    ...
    handleBeginFrame(rawTimeStamp);
  }
  void handleBeginFrame(Duration rawTimeStamp) {
      //执行_transientCallbacks中的回调
      ...
  }
  void _handleDrawFrame() {
    ...
    handleDrawFrame();
  }
  void handleDrawFrame() {
      //执行_persistentCallbacks和_postFrameCallbacks中的回调
      ...
  }

RenderBinding

flutter/lib/src/rendering/binding.dart

mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
  @override
  void initInstances() {
    super.initInstances();
    _instance = this;
    ...
    //addPersistentFrameCallback会将drawFrame函数加入到_persistentCallbacks中,这样在Engine通知Framework渲染的时候会调用到drawFrame
    addPersistentFrameCallback(_handlePersistentFrameCallback);
    initMouseTracker();
  }
  void _handlePersistentFrameCallback(Duration timeStamp) {
    drawFrame();
  }
  @protected
  void drawFrame() {
    assert(renderView != null);
    pipelineOwner.flushLayout();
    pipelineOwner.flushCompositingBits();
    pipelineOwner.flushPaint();
    //在compositeFrame中会调用_window.render(scene),也就是将组合好的layer提交给engine
    renderView.compositeFrame(); // this sends the bits to the GPU
    pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
  }
}

WidgetsBinding

flutter/lib/src/widgets/binding.dart,

mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
    @override
    void initInstances() {
        super.initInstances();
        _instance = this;
        _buildOwner = BuildOwner();
        //widget rebuild的时候会调用onBuildScheduled
        buildOwner.onBuildScheduled = _handleBuildScheduled;
        window.onLocaleChanged = handleLocaleChanged;
        window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
        SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
        FlutterErrorDetails.propertiesTransformers.add(transformDebugCreator);
      }
      void _handleBuildScheduled() {
          ...
          ensureVisualUpdate();//逻辑定义在SchedulerBinding中
      }
      @override
      void drawFrame() {
          if (renderViewElement != null)
            buildOwner.buildScope(renderViewElement);//将标记为dirty的element进行rebuild
          super.drawFrame();
          buildOwner.finalizeTree();
      }
}   


setState后,Framework层通知Engine层

framework.dart中,将需要rebuild的element标记为dirty,同时调用onBuildScheduled;

void setState(VoidCallback fn) {
    _element.markNeedsBuild();
}
void markNeedsBuild() {
    _dirty = true;
    owner.scheduleBuildFor(this);
}
 void scheduleBuildFor(Element element) {
     if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
      _scheduledFlushDirtyElements = true;
      onBuildScheduled();//就是WidgetsBinding初始化时设置的_handleBuildScheduled
    }
    _dirtyElements.add(element);
    element._inDirtyList = true;
 }

WidgetsBinding的初始化中,设置_handleBuildScheduled为owner的 onBuildScheduled 

void _handleBuildScheduled() {
      ...
      ensureVisualUpdate();//逻辑定义在SchedulerBinding中
  }

SchedulerBinding中,会调用window的接口通知Engine有UI需要刷新

 void ensureVisualUpdate() {//有element rebuild的时候会调用到这里
    switch (schedulerPhase) {
      case SchedulerPhase.idle:
      case SchedulerPhase.postFrameCallbacks:
        scheduleFrame();
        return;
      case SchedulerPhase.transientCallbacks:
      case SchedulerPhase.midFrameMicrotasks:
      case SchedulerPhase.persistentCallbacks:
        return;
    }
  }
  void scheduleFrame() {
    ...  
    ensureFrameCallbacksRegistered();
    window.scheduleFrame();//通知Engine有UI需要更新
    _hasScheduledFrame = true;
  }

Vsync到来时,Engine通知Framework进行渲染、并把数据提交给Engine

在Vsync信号到来时,Engine会调用window.onBeginFrame和window.onDrawFrame,告诉Framework进行渲染 ;关键是,window.onBeginFrame和window.onDrawFrame是怎么设置上的呢? 

SchedulerBinding中,每次Framework通知Engine有UI需要更新前,都会ensure window.onBeginFrame和window.onDrawFrame是否设置好,如果没有的话,会设置上;

void scheduleFrame() {
    ...  
    ensureFrameCallbacksRegistered();
    window.scheduleFrame();//通知Engine有UI需要更新
    _hasScheduledFrame = true;
  }
  @protected
  void ensureFrameCallbacksRegistered() {//设置Engine在Vsync信号来的时候通知framework进行渲染的接口
    window.onBeginFrame ??= _handleBeginFrame;
    window.onDrawFrame ??= _handleDrawFrame;
  }

_handleDrawFrame中执行的是执行_persistentCallbacks和_postFrameCallbacks中的回调;那么,_persistentCallbacks又是什么时候设置好的呢?

RenderBinding中,初始化的时候,会将drawFrame加入到_persistentCallbacks中

@override
  void initInstances() {
    super.initInstances();
    ...
    //addPersistentFrameCallback会将drawFrame函数加入到_persistentCallbacks中,这样在Engine通知Framework渲染的时候会调用到drawFrame
    addPersistentFrameCallback(_handlePersistentFrameCallback);
    ...
  }
  void _handlePersistentFrameCallback(Duration timeStamp) {
    drawFrame();
  }
  @protected
  void drawFrame() {
    assert(renderView != null);
    pipelineOwner.flushLayout();
    pipelineOwner.flushCompositingBits();
    pipelineOwner.flushPaint();
    //在compositeFrame中会调用_window.render(scene),也就是将组合好的layer提交给engine
    renderView.compositeFrame(); // this sends the bits to the GPU
    pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
  }

WidgetsBinding中,复写了drawFrame,所以会,先rebuild element,然后layout、composite、paint,再将组合好的layer提交给engine;

@override
  void drawFrame() {
      if (renderViewElement != null)
        buildOwner.buildScope(renderViewElement);//将标记为dirty的element进行rebuild
      super.drawFrame();
      buildOwner.finalizeTree();
  }


参考

1、Flutter渲染流程简析

2、Flutter运行机制-从启动到显示

3、什么是Mixin