Flutter 源码学习 pt.1 开始

78 阅读2分钟

Code

void _removeAt(int index) {
    // The list holding the listeners is not growable for performances reasons.
    // We still want to shrink this list if a lot of listeners have been added
    // and then removed outside a notifyListeners iteration.
    // We do this only when the real number of listeners is half the length
    // of our list.
    _count -= 1;
    if (_count * 2 <= _listeners.length) {
      final List<VoidCallback?> newListeners = List<VoidCallback?>.filled(_count, null);

      // Listeners before the index are at the same place.
      for (int i = 0; i < index; i++) {
        newListeners[i] = _listeners[i];
      }

      // Listeners after the index move towards the start of the list.
      for (int i = index; i < _count; i++) {
        newListeners[i] = _listeners[i + 1];
      }

      _listeners = newListeners;
    } else {
      // When there are more listeners than half the length of the list, we only
      // shift our listeners, so that we avoid to reallocate memory for the
      // whole list.
      for (int i = index; i < _count; i++) {
        _listeners[i] = _listeners[i + 1];
      }
      _listeners[_count] = null;
    }
  }

Framework 代码总是性能取向的,Fixed List 可以尽可能的降低List的扩容机制浪费的内存空间。

tip:

  • List<VoidCallback?>.filled(_count, null)
  • keep index of listener: 使用截断和copy,避免普通removeAt只有_closeGap,未优化内存使用
  • 最后的_listeners[_count] = null左移至后清除引用
 // Otherwise we put all the null references at the end.
        for (int i = 0; i < newLength; i += 1) {
          if (_listeners[i] == null) {
            // We swap this item with the next not null item.
            int swapIndex = i + 1;
            while (_listeners[swapIndex] == null) {
              swapIndex += 1;
            }
            _listeners[i] = _listeners[swapIndex];
            _listeners[swapIndex] = null;
          }
        }

tip:

  • 遍历到被移除的Listener, 开始swap后边不为null的index,并将swapIndex
  • _reentrantlyRemovedListeners = 0;单线程模型,仍旧需要一些手段同步数据
class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> {}

tip:

  • ValueNotifier<T> 通过继承拥有了ChangeNotifier,拥有注册和管理Listener的能力,实现ValueListenable<T> 拥有管理数据的抽象能力, 这种定义方式写法和写法习惯Java有一些区别,更像Rust的 StructImpl 分离的形式,提高了抽象能力,易于组合。

class _MergingListenable extends Listenable {
  _MergingListenable(this._children);

  final List<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(", ")}])';
  }
}

这个类,被从继承ChangeNotifier 转换为Listenable, 提交记录为Fix Listenable.merge to not leak, 这个内存泄漏可能会被触发当多次调用removeListener, 系统代码还是很难写,测试用例发现了这个问题。

tip

  • Listenable.merge, 在需要相应多个监听时很有用,React 的基础应该就是 Listenable。