Flutter中的Key,LocalKey,GlobalKey... And More

news/2023/12/9 16:50:20

开始

从这一篇文章开始,花时间慢慢阅读源码,从web前端角度看Flutter,然后也把一些收获也分享给大家。
React和React Native受到Facebook条款限制,大公司们(主要BAT)都开始若有所思,RN也似乎一下掉下了神坛,同志们,此时此刻正是Flutter当立的时候,大家一起跨进新的时代!

各种各样的Key

立马跳到framework.dart文件(这个文件一看名字就很重要啦),Flutter代码的组织并不像Java反而倾向于JS这种组织方式,一个文件里面塞着不同的Class(当然他们之间肯定有联系的),其实个人更倾向于Java那种一个类一个文件,阅读和分析感觉都比较方便舒服。
framework.dart一开始你就会遇到几个名词:Key,LocalKey,UniqueKey等等。
clipboard.png

一下子冒出几个兄弟来,得一个一个分清楚他们的各有什么能力。

key的作用

首先key有何用尼?
Flutter是受React启发的,所以Virtual Dom的diff算法也参考过来了(应该是略有修改),在diff的过程中如果节点有Key来比较的话,能够最大程度重用已有的节点(特别在列表的场景),除了这一点这个Key也用在很多其他的地方这个以后会总结一下。总之,这里我们可以知道key能够提高性能,所以每个Widget都会构建方法都会有一个key的参数可选,贯穿着整个框架。

key之间的关系

先上图:

clipboard.png

这里就是Key的类型层级关系,可以看到:
Key有两个重要的子类:LocalKey 和 GlobalKey,而他们各自也有不同的子类实现,接下来会继续深入分析。

普通的Key

他们的老大哥Key,这个Key的实现有点特别。

@immutable
abstract class Key {
  /// Construct a [ValueKey<String>] with the given [String].
  ///
  /// This is the simplest way to create keys.
  const factory Key(String value) = ValueKey<String>;

  /// Default constructor, used by subclasses.
  ///
  /// Useful so that subclasses can call us, because the Key() factory
  /// constructor shadows the implicit constructor.
  const Key._();
}

看上去很简单,没有什么特别方法的实现,那为啥特别尼,我个人认为这种特别来自Dart语言的一些特性(其实是Dart语言基础太浅,大神用的太溜)。

const Key._();

首先这里用到命名构造函数(named constructors),大致作用就是给构造函数加多一个有意义的名称,能够让使用者更容易明白各个构造函数的区别(因为类似Java这样,只能靠参数列表来区分确实容易造成混乱)。这里是一个空的实现(并不是Java那一种抽象方法)这里来源一个建议 传送门;

const factory Key(String value) = ValueKey<String>;

这里就是Key默认构造函数(只能有一个默认构造函数,哪怕修改参数列表也不行,之后你只能定义命名构造函数了),但是跟Java又有点不一样啊,首先是factory这个关键字,这是Dart语言内置了对工厂模式的支持(其实大部分语言都可以支持这种模式,这里语言层面上再强化了),而加了这个关键字会怎样?我们知道构建方法返回的一般都是当前类所刚构建的对象,但是加上factory关键字之后你可以修改返回的值,可以让返回的对象是之前已经创建好的,也可以返回这个类的子类对象。
这里还有涉及到一个factory redirect(官网貌似没有介绍,估计新加的语法)传送门
等效于

const factory Key(String value) => new ValueKey<String>(value);

所以这里其实返回了一个ValueKey。

ValueKey

顺藤摸瓜来到ValueKey,而ValueKey其实就是LocalKey的一个子类,但是LocalKey并没有特别的实现只是简单调用了Key._()构造函数。而ValueKey则是:

class ValueKey<T> extends LocalKey

构造函数需要传入一个value的参数:

const ValueKey(this.value);

ValueKey是一个泛型类,并且覆盖了自身的operator==方法(跟 C++覆盖操作符一样),调用了目标类型T的运算符==来比较,当然覆盖了operator==方法也需要覆盖获取hashCode的方法(道理跟Java一样)。所以ValueKey的比较取决于value的operator==的实现,例如Value是字符串类型那就是内容的比较。

ObjectKey

构造函数跟ValueKey差不多:

const ObjectKey(this.value);

虽然同样覆盖了自身的operator==方法,但是它调用的是identical()方法,所以比较的是value的引用。

UniqueKey

也没有特别的实现,没有覆盖operator==方法,所以UniqueKey比较的时候,也就比较引用了(Object默认的operator==调用的就是identical()方法)。

GlobalKey

abstract class GlobalKey<T extends State<StatefulWidget>> extends Key

也是一个泛型类型,但是T必须要继承自State<StatefulWidget>,可以说这个GlobalKey专门用于组件了。
再看:

static final Map<GlobalKey, Element> _registry = <GlobalKey, Element>{};

GlobalKey里含有一个Map,key和value分别为自身和Element。
那什么时候会用到这个Map尼?
跟踪代码很快就找到Element类的mount方法:

void mount(Element parent, dynamic newSlot) {
    ...
    if (widget.key is GlobalKey) {
      final GlobalKey key = widget.key;
      key._register(this);
    }
   ...
  }

可见GlobalKey会在组件Mount阶段把自身放到一个Map里面缓存起来。
缓存又有何作用尼?
答案依然是为了性能。
思考一个场景,A页面是一个商品列表有许多商品图片(大概就单列这样),B页面是一个商品详情页(有商品大图),当用户在A页面点击一个其中详情,可能会出现一个过渡动画,A页面的商品图片慢慢放大然后下面的介绍文字也会跟着出现,然后就这样平滑的过渡到B页面。
此时A页面和B页面都其实共用了一个商品图片的组件,B页面没必要重复创建这个组件可以直接把A页面的组件“借”过来。
使用GlobalKey的组件生命周期是如何的尼,这里暂时挖一个坑先,哈哈。
总之框架要求同一个父节点下子节点的Key都是唯一的就可以了,GlobalKey可以保证全局是唯一的,所以GlobalKey的组件能够依附在不同的节点上。
而从GlobalKey对象上,你可以得到几个有用的属性currentElement,currentWidget,currentState。

GlobalObjectKey

GlobalObjectKey跟LocalObjectKey也差不多,不同点就在与它是Global的。

LabeledGlobalKey

LabeledGlobalKey是用于调试的。

结束

这是第一篇开始深入框架代码的文章,代码阅读还不是很全面,很有可能会有错漏,如有发现,希望能够及时指正。


http://www.niftyadmin.cn/n/4135102.html

相关文章

2003服务器双系统,分享WindowsXP Windows Server2003双系统启动菜单的方法

今天来聊聊一篇关于分享WindowsXP Windows Server2003双系统启动菜单的方法的文章,现在就为大家来简单介绍下分享WindowsXP Windows Server2003双系统启动菜单的方法,希望对各位小伙伴们有所帮助。方法如下&#xff1a;1、安装好双操作系统的电脑(WindowsXP系统和Windows Serve…

在学习ArcGIS Server时无法在web服务器上启动调试。调试失败,因为没有启用集成windows身份验证...

C#中ASP.NET Web应用程序编译时的错误&#xff1a;无法在web服务器上启动调试。调试失败&#xff0c;因为没有启用集成windows身份验证。 解决:打开IIS&#xff0c;在IIS里查看站点信息(属性)&#xff0c;选择“目录安全性”&#xff0c;点击“匿名访问和身份验证控制”右边的“…

findContours 轮廓查找

物体的轮廓勾勒出了物体的整体形状&#xff0c;物体形状的边界像素一起组合成了轮廓。 灰度图像边界的明显特征是边界两侧灰度级的突变&#xff0c;根据这个特征&#xff0c;使用Sobel、拉普拉斯或Canny之类的边缘检测算子可以有效的检测到物体的边界&#xff0c;所有连续的边界…

【Spring Boot】开发环境热部署

开发环境热部署 在实际的项目开发调试过程中会频繁地修改后台类文件&#xff0c;导致需要重新编译、重新启动&#xff0c;整个过程非常麻烦&#xff0c;影响开发效率。下面介绍Spring Boot如何解决这个问题。 1.devtools实现原理 我们在开发调试Spring Boot项目时&#xff0…

spring配置aop事务

spring配置事务两种方式1,注解Transactional2.xml方式 下面主要对xml方式配置spring事务进行说明 原理:使用aop(面向切面编程)对springz中的事务进行管理(同一session下完成一项不可细分的功能/业务需求) 主要分3部 (1)添加transactionManager事务管理器(aop中的切面) (2)配置事…

linux 0.11 内核学习 -- sched.c,调度进程。

/* * 2010-1-21 * 该文件时内核中有关任务调度的函数程序&#xff0c;其中包含基本函数sleep_on&#xff0c; * wakeup&#xff0c;schedule等&#xff0c;以及一些简单的系统调用。同时将软盘的几个操作 * 函数也放置在这里。 * * schedule函数首先对所有的任务检查&#xff…

Liferay 6.2 改造系列之十六:关闭OpenID模式的单点登录

在/portal-master/portal-impl/src/portal.properties文件中&#xff0c;有如下配置&#xff1a; # # Set this to true to enable OpenId authentication. If set to true, then the # property "auto.login.hooks" must contain a reference to the class # com.li…

学习使用笔和纸。

写信&#xff0c;是70年代人最后演绎的浪漫。01年我在深圳闯荡的三个月&#xff0c;每天必做的两件事&#xff1a;一是晚上11点离开旅馆到街上买磁卡找个电话亭&#xff0c;向刚刚熄灯的女朋友寝室楼道拨电话&#xff0c;然后用各种姿势耗一个小时。二就是找个网吧写信&#xf…

tyvj1098 任务安排

描述 N个任务排成一个序列在一台机器上等待完成&#xff08;顺序不得改变&#xff09;&#xff0c;这N个任务被分成若干批&#xff0c;每批包含相邻的若干任务。从时刻0开始&#xff0c;这些任务被分批加工&#xff0c;第i个任务单独完成所需的时间是Ti。在每批任务开始前&…

一步一步搭建 PHP 服务器环境

group_5622_0这两天翻了翻之前的技术文档&#xff0c;发现有一篇值得拿出来和大家分享&#xff1a;如何给一台全新的阿里云服务器&#xff0c;搭建环境 —— 来部署 PHP 项目&#xff0c;Node.js 项目等。 让我们开始吧&#xff1a; 1. 利用 Docker 制作 Centos 服务器2. 安装 …

创建模板化的 ASP.NET 用户控件

可以创建实现模板的用户控件&#xff0c;这是 ASP.NET 的一项功能&#xff0c;它允许将控件数据与其表示形式相分离。模板化控件不提供用户界面。编写它则是为了实现一个命名容器以及包含属性和方法可由宿主页访问的类。 用户控件的用户界面由页面开发人员在设计时提供。开发人…

linux 0.11 内核学习 -- keyboard.s,键盘原来是这么干的。

/* * linux/kernel/keyboard.S * * (C) 1991 Linus Torvalds */ /* * Thanks to Alfred Leung for US keyboard patches * Wolfgang Thiel for German keyboard patches * Marc Corsini for the French keyboard */ #include <linux/config.h> // 内核配置头文件 .tex…

eclipse配置tomcat及修改tomcat默认根目录

1.安装eclipse for j2ee和tomcat&#xff1b; 2.下载tomcat对eclipse的插件&#xff1a;http://www.eclipsetotale.com/tomcatPlugin.html 下载后&#xff0c;解压。解压后的文件放到eclipse的plug目录中&#xff0c;重启后可看见tomcat的图标&#xff08;下载3.3.1版本的没有图…

关于CoDeSys OPC ua配置的记录

1.创建一个简单的CoDeSys程序,TEST001. 在Device中配置网关连接. 其中, PLC_PRG中设置了局部变量, 在GVL_XJ中添加全局变量. 2.在device上右键->添加对象->符号配置. 3.对符号配置进行属性设置,勾选支持opc ua特性. 4. 勾选需要的节点. 5.编译后下载. 附: opc客户端浏览节…

VC++之MFC的五大批判

VC之MFC的五大批判 写在本文之前算起来&#xff0c;我用Visual C也有将近5年的历史了。在这期间&#xff0c;我也曾涉猎过Visual Basic和Delphi&#xff0c;但都是浅尝而止&#xff1b;Visual C始终是我的主业。可是努力的成果如何呢&#xff1f;我用Delphi作出了十多个有规模的…

SpringMVC源码分析6:SpringMVC的视图解析原理

SpringMVC视图机制详解[附带源码分析] 目录 前言重要接口和类介绍源码分析编码自定义的ViewResolver总结参考资料前言 SpringMVC是目前主流的Web MVC框架之一。 如果有同学对它不熟悉&#xff0c;那么请参考它的入门blog&#xff1a;http://www.cnblogs.com/fangjian0423/p/sp…
最新文章