上文,我们大致分析了ChangeNotifierProvider
和Consumer
的源码,但由于很多回调都是系统触发的,导致整个渲染的原理我们还没有盘清楚,带着之前遗留的问题,我们通过调试代码,来试图解开这些秘密。
1 我们在使用
ChangeNotifierProvider
的时候,最终是包装成_Delegate
的子类_CreateInheritedProvider
,然而createElement
是谁调的
2 分析Consumer
,最终在调用builder
的时候使用到了系统回调context
,context
的类型为什么是SingleChildStatelessElement
3 在给builder
传递参数的时候,使用的Provider.of
最终是使用(context) Element
类的_inheritedWidgets
存储的InheritedElement
,最终应用层拿到的T实际是inheritedElement.value
,那InheritedElement
和T
又是如何建立关系的
第一个问题:createElement
,通过断点代码
_InheritedProviderScope.createElement (inherited_provider.dart:310)
Element.inflateWidget (framework.dart:3564)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
SingleChildWidgetElementMixin.mount (nested.dart:223)
--------------------------------------------------------------------------------------------------
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
_NestedHookElement.mount (nested.dart:188)
--------------------------------------------------------------------------------------------------
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
_InheritedProviderScopeElement.performRebuild (inherited_provider.dart:426)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
--------------------------------------------------------------------------------------------------
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
SingleChildWidgetElementMixin.mount (nested.dart:223)
--------------------------------------------------------------------------------------------------
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
_NestedHookElement.mount (nested.dart:188)
--------------------------------------------------------------------------------------------------
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
--------------------------------------------------------------------------------------------------
SingleChildWidgetElementMixin.mount (nested.dart:223)
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
RenderObjectToWidgetElement._rebuild (binding.dart:1252)
RenderObjectToWidgetElement.mount (binding.dart:1223)
--------------------------------------------------------------------------------------------------
RenderObjectToWidgetAdapter.attachToRenderTree. (binding.dart:1165)
BuildOwner.buildScope (framework.dart:2683)
--------------------------------------------------------------------------------------------------
RenderObjectToWidgetAdapter.attachToRenderTree (binding.dart:1164)
WidgetsBinding.attachRootWidget (binding.dart:974)
WidgetsBinding.scheduleAttachRootWidget. (binding.dart:955)
_rootRun (zone.dart:1182)
_CustomZone.run (zone.dart:1093)
_CustomZone.runGuarded (zone.dart:997)
_CustomZone.bindCallbackGuarded. (zone.dart:1037)
_rootRun (zone.dart:1190)
_CustomZone.run (zone.dart:1093)
_CustomZone.bindCallback. (zone.dart:1021)
Timer._createTimer. (timer_patch.dart:18)
_Timer._runTimers (timer_impl.dart:397)
_Timer._handleMessage (timer_impl.dart:428)
_RawReceivePortImpl._handleMessage (isolate_patch.dart:168)
我们看到,堆栈非常长,我们先从上往下看,inflateWidget
主要作用应该是将布局文件实例化为View,ComponentElement
调用mount
时,最终调用到了Element
的inflateWidget
。
从下往上看,是应用启动的流程
main.dart
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..attachRootWidget(app)
..scheduleWarmUpFrame();
}
widgets/binding.dart
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
}
我们写一个app,入口都会是main
函数,在Flutter App中main
函数会调用runApp()
方法,这里首先会调用ensureInitialized
来初始化WidgetsBinding
单例对象,WidgetsFlutterBinding
继承BindingBase
抽象类,并且附带7个mixin,会先调用父类的构造函数
BindingBase() {
developer.Timeline.startSync('Framework initialization');
assert(!_debugInitialized);
initInstances();
assert(_debugInitialized);
assert(!_debugServiceExtensionsRegistered);
initServiceExtensions();
assert(_debugServiceExtensionsRegistered);
developer.postEvent('Flutter.FrameworkInitialization', {});
developer.Timeline.finishSync();
}
BindingBase
构造的时候调用initInstances
和initServiceExtensions
完成以下的工作:
- 执行initInstances()方法会依次调用到每一个mixin来初始化一些状态;
- 执行initServiceExtensions方法会依次调用WidgetsBinding,RendererBinding,SchedulerBinding,ServicesBinding,BindingBase这5个类,主要是根据不同的包(release/profile/debug)调用registerServiceExtension()方法来注册各种扩展服务用于debug。
mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
@override
void initInstances() {
super.initInstances();
_instance = this;
assert(() {
_debugAddStackFilters();
return true;
}());
// Initialization of [_buildOwner] has to be done after
// [super.initInstances] is called, as it requires [ServicesBinding] to
// properly setup the [defaultBinaryMessenger] instance.
_buildOwner = BuildOwner();
buildOwner.onBuildScheduled = _handleBuildScheduled;
window.onLocaleChanged = handleLocaleChanged;
window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
FlutterErrorDetails.propertiesTransformers.add(transformDebugCreator);
}
WidgetsBinding初始化过程会设置window的如下回调方法:
- onLocaleChanged
- onAccessibilityFeaturesChanged
其它几种Binding
暂时不展开说,继续围绕WidgetsBinding
来深入分析,ensureInitialized
拿到了WidgetsBinding
的单例对象,调用attachRootWidget
void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
attachRootWidget(rootWidget);
});
}
scheduleAttachRootWidget
添加异步任务attachRootWidget
,Timer.run
官方给的解释是尽快执行一个异步任务,其实就是把attachRootWidget
这个任务异步来执行,不影响当前程序继续执行
/**
* Runs the given [callback] asynchronously as soon as possible.
*
* This function is equivalent to `new Timer(Duration.zero, callback)`.
*/
static void run(void Function() callback) {
new Timer(Duration.zero, callback);
}
/// Takes a widget and attaches it to the [renderViewElement], creating it if
/// necessary.
///
/// This is called by [runApp] to configure the widget tree.
///
/// See also:
///
/// * [RenderObjectToWidgetAdapter.attachToRenderTree], which inflates a
/// widget and attaches it to the render tree.
void attachRootWidget(Widget rootWidget) {
_readyToProduceFrames = true;
_renderViewElement = RenderObjectToWidgetAdapter(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget,
).attachToRenderTree(buildOwner, renderViewElement as RenderObjectToWidgetElement);
}
来到了attachRootWidget
的实现,通过RenderObjectToWidgetAdapter
将传入的Widget
转成Element
,至此我们知道,Widget
和Element
建立了关系,我们再详细分析下renderView
和RenderObjectToWidgetAdapter
这个类
rendering/binding.dart
mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
@override
void initInstances() {
super.initInstances();
_instance = this;
_pipelineOwner = PipelineOwner(
onNeedVisualUpdate: ensureVisualUpdate,
onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
);
window
..onMetricsChanged = handleMetricsChanged
..onTextScaleFactorChanged = handleTextScaleFactorChanged
..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
..onSemanticsAction = _handleSemanticsAction;
initRenderView();
_handleSemanticsEnabledChanged();
assert(renderView != null);
addPersistentFrameCallback(_handlePersistentFrameCallback);
initMouseTracker();
}
void initRenderView() {
assert(!_debugIsRenderViewInitialized);
assert(() {
_debugIsRenderViewInitialized = true;
return true;
}());
renderView = RenderView(configuration: createViewConfiguration(), window: window);
renderView.prepareInitialFrame();
}
renderView
是在RendererBinding
初始化时候创建的,并将renderView
存储在_pipelineOwner.rootNode
,代码如下:
set renderView(RenderView value) {
assert(value != null);
_pipelineOwner.rootNode = value;
}
再来看RenderObjectToWidgetAdapter
类,这个类非常重要,它建立起了Widget
和Element
的关联
class RenderObjectToWidgetAdapter extends RenderObjectWidget {
/// Creates a bridge from a [RenderObject] to an [Element] tree.
///
/// Used by [WidgetsBinding] to attach the root widget to the [RenderView].
RenderObjectToWidgetAdapter({
this.child,
this.container,
this.debugShortDescription,
}) : super(key: GlobalObjectKey(container));
@override
RenderObjectToWidgetElement createElement() => RenderObjectToWidgetElement(this);
RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement element ]) {
if (element == null) {
owner.lockState(() {
element = createElement();
assert(element != null);
element.assignOwner(owner);
});
owner.buildScope(element, () {
element.mount(null, null);
});
// This is most likely the first time the framework is ready to produce
// a frame. Ensure that we are asked for one.
SchedulerBinding.instance.ensureVisualUpdate();
} else {
element._newWidget = this;
element.markNeedsBuild();
}
return element;
}
是RenderObjectWidget
的子类,构造函数有三个参数child
、container
、debugShortDescription
,attachToRenderTree
里如果element
没有创建,就创建并返回它,如果创建了,就会使用已经创建的element
。,在创建element
的时候createElement
调用了,我们本文开始设置的问题1终于有了答案,createElement
是RenderObjectToWidgetAdapter
调用的,发生在创建element
的时候,而调用createElement
的时候,将this
也就是RenderObjectToWidgetAdapter
对象作为参数层层传递,最终给了Element
,而this
本身存储了Widget
,存在了Element
的widget
成员变量中
abstract class Element extends DiagnosticableTree implements BuildContext {
/// Creates an element that uses the given widget as its configuration.
///
/// Typically called by an override of [Widget.createElement].
Element(Widget widget)
: assert(widget != null),
_widget = widget;
Element _parent;
最终传递给抽象类Element
构造函数中的widget
也是RenderObjectToWidgetAdapter
类的对象,element
第一次创建后会调用element.mount(null, null);
并出现这些堆栈
SingleChildWidgetElementMixin.mount (nested.dart:223)
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
RenderObjectToWidgetElement._rebuild (binding.dart:1252)
RenderObjectToWidgetElement.mount (binding.dart:1223)
--------------------------------------------------------------------------------------------------
RenderObjectToWidgetAdapter.attachToRenderTree. (binding.dart:1165)
BuildOwner.buildScope (framework.dart:2683)
--------------------------------------------------------------------------------------------------
RenderObjectToWidgetAdapter.attachToRenderTree (binding.dart:1164)
WidgetsBinding.attachRootWidget (binding.dart:974)
WidgetsBinding.scheduleAttachRootWidget. (binding.dart:955)
_rootRun (zone.dart:1182)
_CustomZone.run (zone.dart:1093)
_CustomZone.runGuarded (zone.dart:997)
_CustomZone.bindCallbackGuarded. (zone.dart:1037)
_rootRun (zone.dart:1190)
_CustomZone.run (zone.dart:1093)
_CustomZone.bindCallback. (zone.dart:1021)
Timer._createTimer. (timer_patch.dart:18)
_Timer._runTimers (timer_impl.dart:397)
_Timer._handleMessage (timer_impl.dart:428)
_RawReceivePortImpl._handleMessage (isolate_patch.dart:168)
继续看inflateWidget
framework.dart
Element inflateWidget(Widget newWidget, dynamic newSlot) {
assert(newWidget != null);
final Key key = newWidget.key;
if (key is GlobalKey) {
final Element newChild = _retakeInactiveElement(key, newWidget);
if (newChild != null) {
assert(newChild._parent == null);
assert(() {
_debugCheckForCycles(newChild);
return true;
}());
newChild._activateWithParent(this, newSlot);
final Element updatedChild = updateChild(newChild, newWidget, newSlot);
assert(newChild == updatedChild);
return updatedChild;
}
}
final Element newChild = newWidget.createElement();
assert(() {
_debugCheckForCycles(newChild);
return true;
}());
newChild.mount(this, newSlot);
assert(newChild._debugLifecycleState == _ElementLifecycle.active);
return newChild;
}
inflateWidget
是抽象类Element
的方法,这里的参数newWidget
是RenderObjectToWidgetElement.mount
层层传递进去的,就是存储在RenderObjectToWidgetAdapter
中的child
,也就是我们在runApp
时候传递的rootWidget
。
随着inflateWidget
的执行,newWidget.createElement
调用,如果newWidget
是StatefulWidget
就会执行StatefulElement(this);
abstract class StatefulWidget extends Widget {
/// Initializes [key] for subclasses.
const StatefulWidget({ Key key }) : super(key: key);
/// Creates a [StatefulElement] to manage this widget's location in the tree.
///
/// It is uncommon for subclasses to override this method.
@override
StatefulElement createElement() => StatefulElement(this);
如果widget
是InheritedProvider
,那就会执行InheritedProvider
的createElement
,如果是_InheritedProviderScope
,就会执行_InheritedProviderScope
的createElement
。当调用newWidget.createElement
时,会产生多态。
至此,我们已经清楚了,
final Element newChild = newWidget.createElement();
createElement
可以创建任何Element
的子类对象,下面是调用newChild.mount
,由于newChild
的类型不同,mount
调用也是Element
子类或者说实现类的mount
方法,这里也解释了,mount
方法就是这个时候调用的。我们通常使用的mounted
的定义如下
abstract class State with Diagnosticable {
bool get mounted => _element != null;
}
这里也层面的解释了一个问题,是现有Element
对象还是先调用mount
方法,答案是:先有Element
对象后调用的mount
方法,当我们一个widget
被加到Element tree后,mounted
就应该是true了
newChild.mount(this, newSlot);
如果
newChild
是
_InheritedProviderScopeElement
类型的,会有下面的堆栈:
_CreateInheritedProvider.createState (inherited_provider.dart:605)
_InheritedProviderScopeElement.performRebuild (inherited_provider.dart:424)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
Element.inflateWidget (framework.dart:3569)
Element.updateChild (framework.dart:3327)
ComponentElement.performRebuild (framework.dart:4652)
Element.rebuild (framework.dart:4343)
ComponentElement._firstBuild (framework.dart:4606)
ComponentElement.mount (framework.dart:4601)
这才调用到上文提到的createState
是在_InheritedProviderScopeElement
类中performRebuild
方法执行时候调用的,代码如下
void performRebuild() {
if (_firstBuild) {
_firstBuild = false;
_delegateState = widget.owner._delegate.createState()..element = this;
}
super.performRebuild();
}
这里的widget.owner._delegate
其实就是_Delegate
类的子类_CreateInheritedProvider
的实例,上文已经解释 ,这里不做过多说明,那随着createState
的调用_CreateInheritedProviderState
的对象应运而生,后面就由_delegateState
进行表演了。
结语
本文所分析的都是初始化的流程,并结合上文遗留的问题进行讲解,主要通过启动流程,来搞清楚Widget
和Element
是如何建立关系的,接下来,我们需要聚焦的问题是:
- 当数据发生改变的时候,视图是如何发生变化的(Provider的原理)
- 我们通常使用的
StatefulWidget
视图刷新机制和Provider
有什么不同 -
initState
,setState
的底层原理是什么