服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

从源码看Flutter BuildContext的秘密

日期: 来源:群英传收集编辑:徐宜生

点击上方蓝字关注我,知识会给你力量


我们每次在写Flutter代码的时候,都会看到这个参数——BuildContext,在Android开发中,也经常看见一个类似的东西——Context,它们是不是一样的呢?其实说一样也对,它们都是上下文的关键承载者,但是却也不一样,因为它们本质上是两个不同的概念。在Flutter中,BuildContext的源码如下。

从注释中我们就可以看出,[BuildContext]对象实际上是[Element]对象。[BuildContext]接口是用来阻止对[Element]对象的直接操作,它就是为了避免直接操纵Element类而创建的。

Element是Flutter UI中的一个非常重要的组成,Flutter UI在创建时,会通过Widget的createElement方法创建Element,然后Framework会调用Element实例的mount方法,在这个方法中,根据需要创建RenderObject,并挂载到Element的renderObject属性上,实际的布局和绘制,通常都是通过RenderObject的实现类RenderBox来实现的。

所以,我们甚至可以直接把Context强转为Element,从而调用Element的方法,例如下面的代码。

var size = ((context as Element).findRenderObject() as RenderBox).size;

(context as Element).markNeedsBuild();

在使用BuildContext的时候,我们最常见的一个误区就是下面这个例子。

这段代码很简单,就是在当前页面上路由到一个新的页面,但是我们执行后,上面的代码会报错。

从错误原因上我们可以看到,就是Context的问题,也就是of(context)这个方法。类似的代码风格,我们在Flutter中可以找到很多,例如下面这些。

Navigator.of(context)
Scaffold.of(context).openDrawer()
Theme.of(context).copyWith()
……

就以Navigator.of(context)为例,我们来看下of方法的实现。

可以看到,关键代码就是通过context.findRootAncestorStateOfType()或者是context.findAncestorStateOfType()方法,向上遍历Element tree,并找到最近匹配的NavigatorState。也就是说of实际上是对context跨组件获取数据的一个封装方法。

而我们的Navigator的push操作就是通过找到的NavigatorState来完成的。

那么我们现在来看下上面的那个错误具体是怎么产生的。当我们在build函数中使用Navigator.of(context)的时候,这个context实际上是通过MyApp这个widget创建出来的Element对象,而of方法向上寻找祖先节点的时候(MyApp的祖先节点),其实并不存在MaterialApp,也就没有它所提供的Navigator,所以就出错了。

那么当我们把Scaffold的部分拆成另外一个widget的时候,我们在FirstPage的build函数中,获取的就是FirstPage的BuildContext,然后向上寻找发现了MaterialApp,并找到它提供的Navigator,于是就可以愉快进行页面跳转了。所以要解决这个问题,一般有两个方法,一个就是抽取出一个新的Widget组件,或者是通过Builder组件,为后续Widget创建一个新的BuildContext环境。

所以,看到这里,你可以认为,BuildContext,实际上就是当前Widget在Element树上的句柄。

下面我们就从源码角度,来看下BuildContext的创建与加载的过程。

我们以StatelessWidget为例,在创建StatelessWidget的时候,首先会去createElement,并将当前widget传给Element,即StatelessElement。

在这个Element中,我们发现它的build方法,实际上就是调用了Widget的build方法,同时,传入了this,这个this,实际上就是我们在Widget的build方法中看到的BuildContext,到处,我们终于理清了,为什么BuildContext就是Element了。

同时,正是由于Flutter视图的树形结构,可以让我们很方便的在树上游走,这就需要我们用到它的一些游走的方法。

dependOnInheritedElementInheritedWidgetworking on the base of ancestor's widget and rebuilding when ancestors change
dependOnInheritedWidgetOfExactTypeT?runtime type of widgets or functions or model
describeElementDiagnosticsNodedescriptions of elements
describeMissingAncestorListList of missing ancestors
describeOwnershipChainDiagnosticsNodedescribes the ownership chain to the error report
describeWidgetDiagnosticsNodedescribe the details and working features of the widget
dispatchNotificationvoidbubble notification indicator at the context
findAncestorRenderObjectOfTypeT?runtime type of RenderObjectOfType
findAncestorStateOfTypeT?runtime type of StateOfType
findAncestorWidgetOfExactTypeT?runtime type of WidgetOfExactType
findRenderObjectT?current render object which is created by itSelf
findRootAncestorStateOfTypeT?runtime type ancestor's of given T type stateful widgets instance
getElementForInheritedWidgetOfExactTypeInheritedElement?Type of concrete inheritedWidget subclass
noSuchMethoddynamicdynamic type of method
toStringstringconverting the date to string through .toString methods provided by the framework
visitAncestorElementsvoidworks for the call back return function, call back can not be null
visitChildElementsvoidchildren of the widgets or visitor

这些方法也不用死记硬背,你只需要时刻记得「那几棵树」即可。

向大家推荐下我的网站 https://www.yuque.com/xuyisheng  点击原文一键直达

专注 Android-Kotlin-Flutter 欢迎大家访问



往期推荐


本文原创公众号:群英传,授权转载请联系微信(Tomcat_xu),授权后,请在原创发表24小时后转载。
< END >
作者:徐宜生

更文不易,点个“三连”支持一下

相关阅读

  • 解读SourceMap

  • 大厂技术 坚持周更 精选好文本文为来自 字节教育-成人与创新前端团队 成员的文章,已授权 ELab 发布。SourceMap的用途前端工程打包后代码会与源码产生不一致,当代码运行出错
  • 面对AI的惶恐|预言家周报#213

  • 最近几周,和 Crypto 圈内的朋友聊天,总是聊着聊着话题就转到了 AI ,接着就转不回来了。这就是当红炸子鸡和过气老母鸡的区别。上一轮熊市也有过这个阶段,有一晚凄风苦雨,大家在地
  • 99元订商论,限时季度优惠最后两天!

  • ”《经济学人·商论》年度订阅原价488元,3月25日前限时特惠3个月季度订阅只需99元,史上最低!《经济学人·商论》限时特惠·季度低至¥9999元季度订阅超值权益商论APP核心功能:30
  • 【第2897期】ECMAScript 2023 有哪些更新?

  • 前言阴雨绵绵的开始。今日前端早读课文章由 @CUGGZ 分享,公号:前端充电宝授权。正文从这开始~~ECMAScript 规范每年都会更新一次,ECMAScript 2023 预计将于 6 月左右获得批准,这将
  • 美国国家地理空间情报局发布《NGA战略2025》

  • 点击上方“慧天地”关注‍‍2023年3月,美国国家地理空间情报局(NGA)发布《NGA战略2025》(1.1版)。NGA的2025年战略目标与美国《2018年国防战略》和《2019年国家情报战略》保持一
  • 空军95861部队直招军官(含地理空间信息工程等专业)

  • 点击上方“慧天地”关注‍‍文章来源:大漠神箭,撰文:贺颖慧,视频:王浩东、张文博、江艺,编辑:王浩东,责编:贺春元,总编:赵延年,版权归原作者及刊载媒体所有。满腔青春血,正值报国时砥砺英

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • 从源码看Flutter BuildContext的秘密

  • 点击上方蓝字关注我,知识会给你力量我们每次在写Flutter代码的时候,都会看到这个参数——BuildContext,在Android开发中,也经常看见一个类似的东西——Context,它们是不是一样的
  • 没交易的地方你敢去吗?

  • 阅前提示:全文系虚构。本文对所涉及的基金产品及其他信息、意见等均不构成任何推荐或建议,请读者全面认识基金产品的风险收益特征,根据自身情况自行做出投资决策,市场有风险,投资
  • 今天联合腾讯来给大家送个福利!

  • 今天向大家推荐的是腾讯云技术社区的公众号,是腾讯官方推出的技术知识分享阵地,每周公开腾讯最新的技术工程方案(如微信、健康码、王者荣耀等知名业务的技术架构)、ChatGPT 等行