flutter setState源码分析

我们知道rebuild widget一般是在State里面调用setState,那么rebuild的原理是什么样的呢?

setState会调用element的markNeedsBuild 标记需要rebuild的element,然后调用BuildOwner的

scheduleBuildFor

setState => element.markNeedsBuild(){

    //标记脏了,需要重新绘制

    _dirty = true;

    //每个element都持有同一个owner

    //buildowner在WidgetsFlutterBinding

    //初始化时创建,并且设置了build回调 buildOwner!.onBuildScheduled = 
    // _handleBuildScheduled;
    


    owner!.scheduleBuildFor(this);

}

scheduleBuildFor 里面然后调用_handleBuildScheduled

/// Adds an element to the dirty elements list so that it will be rebuilt
/// when [WidgetsBinding.drawFrame] calls [buildScope].
//将需要build的element添加到列表
//当WidgetsBinding.drawFrame调用buildScope时会用到
=>BuildOwner.scheduleBuildFor(){
    if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
      _scheduledFlushDirtyElements = true;
      onBuildScheduled!();
    }

    _dirtyElements.add(element);
    element._inDirtyList = true;
}

调用栈

==>_handleBuildScheduled()
==>ensureVisualUpdate()
=>SchedulerBinding.scheduleFrame(){
	ensureFrameCallbacksRegistered();
window.scheduleFrame();
_hasScheduledFrame = true;

}
=>window.scheduleFrame();
=>platformDispatcher.scheduleFrame()
=> native PlatformConfiguration_scheduleFrame

然后调用到native层

==>platform_configuration.cc#ScheduleFrame
=> runtime_controller.cc#ScheduleFrame
=>engine.cc#ScheduleFrame
=>animator::RequestFrame
//等待同步信号
=>animator.cc#Animator::AwaitVSync()
=>animator.cc#Animator::BeginFrame
=>shell.cc#OnAnimatorBeginFrame
=>engine_->BeginFrame(frame_target_time, frame_number)
=>runtime_controller_->BeginFrame(frame_time, frame_number);
=>platform_configuration->BeginFrame(frame_time, frame_number){
	tonic::LogIfError(
//调用dart层的 hooks.dart#_beginFrame
      tonic::DartInvoke(begin_frame_.Get(), {
                                                Dart_NewInteger(microseconds),
                                                Dart_NewInteger(frame_number),
                                            }));

  UIDartState::Current()->FlushMicrotasksNow();

native在调用dart层的hooks#_drawFrame 

//调用dart层的 hooks.dart#_drawFrame
  tonic::LogIfError(tonic::DartInvokeVoid(draw_frame_.Get()));

}
//这里会走两个分支,1执行begin_frame_ 2.执行draw_frame_
分支1:=>tonic::LogIfError(
      tonic::DartInvoke(begin_frame_.Get(), {
                                                Dart_NewInteger(microseconds),
                                                Dart_NewInteger(frame_number),
                                            }));


//绘制每一帧之前的回调
=> hooks.dart#_beginFrame
=>platform_dispatcher.dart#_beginFrame
=> window.onBeginFrame
=>SchedulerBinding.dart#_handleBeginFrame
=>handleBeginFrame
==>遍历_transientCallbacks,执行回调
=>调用通过SchedulerBinding.instance!.scheduleFrameCallback注册的回调

//绘制回调
分支2:hooks.dart#_drawFrame
=>windown.onDrawFrame
=>schedulerBinding._handleDrawFrame
//执行_persistentCallbacks,_postFrameCallbacks注册的回调
=>SchedulerBinding.handleDrawFrame()=>

RendererBinding._handlePersistentFrameCallback => WidgetsBinding.drawFrame(){
	if (renderViewElement != null)
  buildOwner!.buildScope(renderViewElement!);
super.drawFrame(); => RendererBinding.drawFrame()
buildOwner!.finalizeTree();

}
=> RendererBinding.drawFrame(){
	pipelineOwner.flushLayout();
	pipelineOwner.flushCompositingBits();
	pipelineOwner.flushPaint();
	if (sendFramesToEngine) {
  		renderView.compositeFrame(); // this sends the bits to the GPU
  		pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
 		 _firstFrameSent = true;
	}
}
=> void compositeFrame() {
  try {
    final ui.SceneBuilder builder = ui.SceneBuilder();
    final ui.Scene scene = layer!.buildScene(builder);
    if (automaticSystemUiAdjustment)
      _updateSystemChrome();
    _window.render(scene);
    scene.dispose();
  } finally {
  }
}


//rebuild列表里的element
buildScope(){
while(){
_dirtyElements[index].rebuild();
}
}
//赋值window.onDrawFrame= SchedulerBinding._handleDrawFrame

//启动app时scheduleWarmUpFrame无需等到同步信号,第一时间显示最近的缓存数据
runApp(app){
	WidgetsFlutterBinding.ensureInitialized()
  ..scheduleAttachRootWidget(app)
  ..scheduleWarmUpFrame();

}=>SchedulerBinding.scheduleWarmUpFrame(){
Timer.run(() {
  assert(_warmUpFrame);
  handleBeginFrame(null);
});
Timer.run(() {
  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();
  _warmUpFrame = false;
  if (hadScheduledFrame)
    scheduleFrame();
});

}


//WidgetsFlutterBinding RendererBinding初始化注册回调到列表_persistentCallbacks 始终存在列表中
addPersistentFrameCallback(_handlePersistentFrameCallback);




window.scheduleFrame => ScheduleFrame
AwaitVSync =>Animator.cc =>Shell => engine => runtime_controller => platform

java -> dart
FlutterJNI =>
platform_view_android_jni_impl.cc => AndroidShellHolder=>Shell => engine => runtime_controller => platform
=>DartInvoke

RuntimeController 是PlatformConfigurationClient

 

总结:setState =>对element做标记需要rebuild
由window.scheduleFrame通知native层等待同步信号,需要回调hooks.dart#_beginFrame,hooks.dart#_drawFrame
=>buildOwner.buildScope =>element.rebuild()=>performRebuild =>build()=>
//比较新旧widget  Element 
_child = updateChild(_child, built, slot);


//layout => Compositing(合成) => paint()
==> RendererBinding.drawFrame(){
	pipelineOwner.flushLayout();
	pipelineOwner.flushCompositingBits();
	pipelineOwner.flushPaint();
	if (sendFramesToEngine) {
  		renderView.compositeFrame(); // this sends the bits to the GPU
  		pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
 		 _firstFrameSent = true;
	}
}


widget比较算法
static bool canUpdate(Widget oldWidget, Widget newWidget) {
  return oldWidget.runtimeType == newWidget.runtimeType
      && oldWidget.key == newWidget.key;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值