Flutter状态管理篇之ChangeNotifier(二)

目录

前言

一、ChangeNotifier定义

1.ChangeNotifier定义

2.Listenable的定义

二、继承体系

三、核心方法解析

1.类结构与属性分析

1.Listenable的定义

2..核心字段

1.属性解析

1._count        

2._listeners

3.为什么不用const []

4._notificationCallStackDepth

5._reentrantlyRemovedListeners

6._debugDisposed

7._debugCreationDispatched

bool _debugCreationDispatched = false;

2. 方法解析

1.debugAssertNotDisposed

2.hasListeners

3.maybeDispatchObjectCreation

4.addListener

5.removeListener

6._removeAt

7.dispose

8.notifyListeners

3. 与_MergingListenable的关系

4. 设计理念和优化

5. 使用场景

6. 注意事项

7. 总结

四、生命周期管理

1. dispose()方法

五、内存跟踪支持(调试)

六、总结

七、参考资料


前言

        上一篇博客介绍了ChangeNotifier的用法,这篇主要介绍ChangeNotifier的实现原理。

        那么,ChangeNotifier 是如何工作的?它内部又是如何维护监听器并发送通知的?本文将从源码角度出发,一步一步带你深入理解 ChangeNotifier 的实现原理。

一、ChangeNotifier定义

1.ChangeNotifier定义

        ChangeNotifier 是一个混入类(mixin class),实现了 Listenable 接口,同时实现了Listenable定义的方法,具备添加、移除监听器的能力。

mixin class ChangeNotifier implements Listenable

        它主要用于在数据发生变化时通知监听者(Listener),从而驱动 UI 更新。

2.Listenable的定义

        我们看一下Listenable的定义,它是一个抽象类,定义了如下的方法:

以下是你提供的 Listenable 抽象类中所有注释的中文翻译版本:abstract class Listenable {/// 抽象的 const 构造函数。这个构造函数使得子类可以提供 const 构造函数,/// 以便它们可以在 const 表达式中使用。const Listenable();/// 返回一个 [Listenable],当给定的任意一个 [Listenable]/// 触发时都会触发该对象。////// 一旦调用了该工厂方法,不得再向可迭代对象中添加或移除项。/// 否则将导致内存泄漏或异常。////// 可迭代对象中可能包含 null,这些值会被忽略。factory Listenable.merge(Iterable<Listenable?> listenables) = _MergingListenable;/// 注册一个回调函数,当对象通知其监听者时会调用该回调。void addListener(VoidCallback listener);/// 从通知对象的回调列表中移除一个先前注册的回调函数。void removeListener(VoidCallback listener);
}

        其中_MergingListenable类的定义如下,它使用一个数组_children保存Litenable类型的数组,当我们调用addListener方法的时候,把Listenable对象加入到数组中,当我们调用removeListener方法的时候,遍历数组移除指定的Listenable。 除此之外,还提供了一个toString方法,用来调试。

class _MergingListenable extends Listenable {_MergingListenable(this._children);final Iterable<Listenable?> _children;@overridevoid addListener(VoidCallback listener) {for (final Listenable? child in _children) {child?.addListener(listener);}}@overridevoid removeListener(VoidCallback listener) {for (final Listenable? child in _children) {child?.removeListener(listener);}}@overrideString toString() {return 'Listenable.merge([${_children.join(", ")}])';}
}

二、继承体系

        Flutter 中关于监听的接口结构如下:

Listenable
├── ValueListenable<T>
│   └── ValueNotifier<T>
└── ChangeNotifier

        Listenable:最基础的接口,定义了 addListener 和 removeListener 方法。

        ValueListenable<T>:扩展了 Listenable,增加了 value 属性。

        ValueNotifier<T>:是一个封装了 value 的 ChangeNotifier。

        ChangeNotifier:可以被继承或混入,具备增删监听器及通知监听器的功能。

三、核心方法解析

        这段代码是 Flutter 中 ChangeNotifier 的核心实现之一,它实现了 Listenable 接口,并通过 mixin 的方式注入到模型类中。以下是对这份源码的详解,包括实现原理和内部机制:

1.类结构与属性分析

1.Listenable的定义

mixin class ChangeNotifier implements Listenable

        使用 mixin class 是Dart 3引入的新特性,允许 mixin 具有构造函数,但此处它没有构造函数。

        实现了Listenable 接口,因此需要实现 addListener、removeListener 方法。

2..核心字段

        ChangeNotifier中定义了几个关键字段,用于管理监听者列表和状态:

1.属性解析
1._count        

int _count = 0;

        作用:记录当前注册的监听者数量。

        用途:_count 表示 _listeners 列表中实际有效的监听者数量(不包括 null 占位符)。它用于快速判断是否有监听者(hasListeners)以及在添加/移除监听者时更新列表状态。

2._listeners

static final List<VoidCallback?> _emptyListeners = List<VoidCallback?>.filled(0, null);
List<VoidCallback?> _listeners = _emptyListeners;

        作用:存储所有注册的监听者(VoidCallback类型,允许null)。
        初始化:

  1. _emptyListeners是一个静态的空列表(长度为 0),用作初始值。

  2. _listeners是一个List<VoidCallback?>,允许存储null,因为在某些情况下(例如通知期间移除监听者),会临时将列表中的某些位置设置为null。

3.为什么不用const []

        注释中提到,const []会创建_ImmutableList类型的对象,而_listeners在运行时需要是固定长度的_GrowableList类型(尽管代码中通过List.filled创建的是固定长度列表,但逻辑上允许动态调整大小)。
          保持_listeners的运行时类型一致(_GrowableList)有助于编译器优化,提高性能。

4._notificationCallStackDepth

int _notificationCallStackDepth = 0;

        作用:跟踪notifyListeners的递归调用深度。
        用途:用于处理通知期间的监听者移除操作。如果在notifyListener执行期间移除监听者,ChangeNotifier会延迟列表的实际缩减,直到所有通知完成(即_notificationCallStackDepth回到 0)。

5._reentrantlyRemovedListeners

int _reentrantlyRemovedListeners = 0;

   &nb

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/89823.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/89823.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大带宽服务器对于高流量网站的作用

随着科学技术的快速发展&#xff0c;越来越多的网站面临着高流量的访问需求&#xff0c;在同一时间中会有着大量的用户进行访问&#xff0c;同时也提高了该企业的知名度&#xff0c;但是这对于服务器的性能需求也在逐渐增高&#xff0c;而大带宽服务器卓越的性能和稳定的传输能…

2025年算法备案发号规律总结与下半年发号预测

上半年发号规律总结图太糊&#xff1f;可看下方表格&#xff08;左划看全表&#xff09;&#x1f447;今年批次算法备案总批次发布时间所发当批算法材料提交时间段审核周期25年第一批第十批2025/3/122025年1月&#xff08;春节前&#xff09;约2个月25年第二批第十一批2025/5/1…

高光谱相机(Hyperspectral Camera)

高光谱相机&#xff08;Hyperspectral Camera&#xff09;高光谱相机&#xff1a;是一种可以采集连续、多达上百个窄波段的光谱信息的成像设备。它的核心特征是&#xff1a;每个像素点都拥有一个完整的光谱曲线&#xff0c;类似于“像素级别的光谱仪”。举例&#xff1a;普通彩…

经典排序算法之归并排序(Merge Sort)

归并算法定义&#xff1a;所谓归并排序是指将两个或两个以上有序的数列&#xff08;或有序表&#xff09;&#xff0c;合并成一个仍然有序的数列&#xff08;或有序表&#xff09;。这样的排序方法经常用于多个有序的数据文件归并成一个有序的数据文件。归并排序相比较之前的排…

Linux系统环境下 Node.js 20 安装实践:glibc 2.17 兼容方案与工具链优化

前言&#xff1a;在 CentOS 7.9 的生产环境中&#xff0c;默认搭载的 glibc 2.17 是系统的核心依赖&#xff0c;直接升级它可能引发稳定性风险。而 Node.js 20 作为较新的运行时&#xff0c;其与 glibc 的兼容性长期困扰着开发者&#xff1a;为什么有些场景下 Node.js 20 能直接…

构建一个简单的Java框架来测量并发执行任务的时间

文章目录一、完整代码二、代码解释1、方法签名2、初始化CountDownLatch3、提交任务到执行器4、任务线程的逻辑5、主线程的逻辑详细解释总结以下代码实现了一个简单的框架&#xff0c;用于测量并发执行任务的时间。它使用了Executor来执行任务&#xff0c;并通过CountDownLatch来…

精通 triton 使用 MLIR 的源码逻辑 - 第001节:triton 的应用简介

项目使用到 MLIR&#xff0c;通过了解 triton 对 MLIR 的使用&#xff0c;体会到 MLIR 在较大项目中的使用方式&#xff0c;汇总一下。1. Triton 概述OpenAI Triton 是一个开源的编程语言和编译器&#xff0c;旨在简化 GPU 高性能计算&#xff08;HPC&#xff09; 的开发&#…

Python爬虫-政务网站自动采集数据框架

前言 本文是该专栏的第81篇,后面会持续分享python爬虫干货知识,记得关注。 本文,笔者将详细介绍一个基于政务网站进行自动采集数据的爬虫框架。对此感兴趣的同学,千万别错过。 废话不多说,具体细节部分以及详细思路逻辑,跟着笔者直接往下看正文部分。(附带框架完整代码…

GitHub 趋势日报 (2025年07月19日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图1054shadPS4695n8n361remote-jobs321maigret257github-mcp-server249open_deep_res…

2025开源组件安全工具推荐OpenSCA

OpenSCA是国内最早的开源SCA平台&#xff0c;继承了商业级SCA的开源应用安全缺陷检测、多级开源依赖挖掘、纵深代码同源检测等核心能力&#xff0c;通过软件成分分析、依赖分析、特征分析、引用识别、合规分析等方法&#xff0c;深度挖掘组件中潜藏的各类安全漏洞及开源协议风险…

旅游管理实训基地建设:筑牢文旅人才培养的实践基石

随着文旅产业的蓬勃发展&#xff0c;行业对高素质、强实践的旅游管理人才需求日益迫切。旅游管理实训基地建设作为连接理论教学与行业实践的关键纽带&#xff0c;既是深化产教融合的重要载体&#xff0c;也是提升旅游管理专业人才培养质量的核心抓手。一、旅游管理实训基地建设…

网络爬虫的相关知识和操作

介绍 爬虫的定义 爬虫&#xff08;Web Crawler&#xff09;是一种自动化程序&#xff0c;用于从互联网上抓取、提取和存储网页数据。其核心功能是模拟人类浏览行为&#xff0c;访问目标网站并解析页面内容&#xff0c;最终将结构化数据保存到本地或数据库。 爬虫的工作原理 …

【vue-6】Vue3 响应式数据声明:深入理解 ref()

在 Vue3 的 Composition API 中&#xff0c;ref() 是最基础也是最常用的响应式数据声明方式之一。它为开发者提供了一种简单而强大的方式来管理组件状态。本文将深入探讨 ref() 的工作原理、使用场景以及最佳实践。 1. 什么是 ref()&#xff1f; ref() 是 Vue3 提供的一个函数&…

HTML常用标签汇总(精简版)

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>简单标记</title> </head><body>&…

【.net core】支持通过属性名称索引的泛型包装类

类/// <summary> /// 支持通过属性名称索引的泛型包装类 /// </summary> public class PropertyIndexer<T> : IEnumerable<T> {private T[] _items;private T _instance;private PropertyInfo[] _properties;private bool _caseSensitive;public Prope…

【机器学习|学习笔记】详解支持向量机(Support Vector Machine,SVM)为何要引入核函数?为何对缺失数据敏感?

【机器学习|学习笔记】详解支持向量机(Support Vector Machine,SVM)为何要引入核函数?为何对缺失数据敏感? 【机器学习|学习笔记】详解支持向量机(Support Vector Machine,SVM)为何要引入核函数?为何对缺失数据敏感? 文章目录 【机器学习|学习笔记】详解支持向量机(…

Bicep入门篇

前言 Azure Bicep 是 ARM 模板的最新版本,旨在解决开发人员在将资源部署到 Azure 时遇到的一些问题。它是一款开源工具,实际上是一种领域特定语言 (DSL),它提供了一种声明式编写基础架构的方法,该基础架构描述了虚拟机、Web 应用和网络接口等云资源的拓扑结构。它还鼓励在…

命名实体识别15年研究全景:从规则到机器学习的演进(1991-2006)

本文精读NRC Canada与NYU联合发表的经典综述《A survey of named entity recognition and classification》&#xff0c;解析NERC技术演进脉络与核心方法论 一、为什么命名实体识别&#xff08;NER&#xff09;如此重要&#xff1f; 命名实体识别&#xff08;Named Entity Rec…

eNSP综合实验(DNCP、NAT、TELET、HTTP、DNS)

1搭建实验拓扑2实验目的学习掌握eNSP中的命令3实验步骤3.1配置连接PC和客户端的交换机(仅以右侧为例)[Huawei]vlan batch 10 20 #创建vlan Info: This operation may take a few seconds. Please wait for a moment...done. [Huawei]un in en [Huawei]interface e0/0/2 [Huawei…

无人系统与安防监控中的超低延迟直播技术应用:基于大牛直播SDK的实战分享

技术背景 在 无人机、机器人 以及 智能安防 等高要求行业&#xff0c;高清视频的超低延迟传输 正在成为影响系统性能与业务决策的重要因素。无论是工业生产线的远程巡检、突发事件的应急响应&#xff0c;还是高风险环境下的智能监控与远程控制&#xff0c;视频链路的传输延迟都…