Flutter状态管理篇之ChangeNotifier(二)

发布于:2025-07-20 ⋅ 阅读:(13) ⋅ 点赞:(0)

目录

前言

一、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;

  @override
  void addListener(VoidCallback listener) {
    for (final Listenable? child in _children) {
      child?.addListener(listener);
    }
  }

  @override
  void removeListener(VoidCallback listener) {
    for (final Listenable? child in _children) {
      child?.removeListener(listener);
    }
  }

  @override
  String 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


网站公告

今日签到

点亮在社区的每一天
去签到