Flutter —— 状态管理 | ScopedModel

4字数 290阅读 399

Flutter 无状态管理相当于 Androi 的mvc模式,数据UI写在一块,写起来简单,但是逻辑代码复杂,
不利于维护,接下来我会逐一解锁Flutter的状态管理。

Scoped Model介绍

Scoped Model 利用 model 的方式,轻松的将数据模型从父 Widget 传递到它的后代,并且此数据
模型实现观察者模式,当数据改变时,会通知实现的子类,重新构建新的子类 Widget 达到数据刷新的目的 。

/// A base class that holds some data and allows other classes to listen to
/// changes to that data.

/// In order to notify listeners that the data has changed, you must explicitly
/// call the [notifyListeners] method.

/// Generally used in conjunction with a [ScopedModel] Widget, but if you do not
/// need to pass the Widget down the tree, you can use a simple [AnimatedBuilder]
/// to listen for changes and rebuild when the model notifies the listeners.

Scoped Model 原理

Model 继承了 Listenable 抽象类,在 Model 中实现了抽象方法,Listenable中体现了注册监听,notifyListener通知子类数据已经改变。

abstract class Model extends Listenable

///注册监听
/// Register a closure to be called when the object notifies its listeners.
void addListener(VoidCallback listener);

///删除监听
/// Remove a previously registered closure from the list of closures that the
/// object notifies.
void removeListener(VoidCallback listener);

///通知监听者
@protected
void notifyListeners() {...}

源码分析

Model源码分析

abstract class Model extends Listenable {
  //创建一个监听的回调集合
  final Set<VoidCallback> _listeners = Set<VoidCallback>();
  int _version = 0;
  int _microtaskVersion = 0;

  /// [listener] will be invoked when the model changes.
  @override
  void addListener(VoidCallback listener) {
    _listeners.add(listener);
  }

  /// [listener] will no longer be invoked when the model changes.
  @override
  void removeListener(VoidCallback listener) {
    _listeners.remove(listener);
  }

  /// Returns the number of listeners listening to this model.
  int get listenerCount => _listeners.length;

  /// Should be called only by [Model] when the model has changed.
  @protected
  void notifyListeners() {
    // We schedule a microtask to debounce multiple changes that can occur
    // all at once.
    if (_microtaskVersion == _version) {
      _microtaskVersion++;
      //调用消息队列
      scheduleMicrotask(() {
        //_version 改变会通知子类数据已改变,在_InheritedModel 这个类中有说明
        _version++;
        _microtaskVersion = _version;

        // Convert the Set to a List before executing each listener. This
        // prevents errors that can arise if a listener removes itself during
        // invocation!
        //执行Callback,通知子类
        _listeners.toList().forEach((VoidCallback listener) => listener());
      });
    }
  }
}

ScopedModel 源码分析

class ScopedModel<T extends Model> extends StatelessWidget {
  /// The [Model] to provide to [child] and its descendants.
  final T model;

  /// The [Widget] the [model] will be available to.
  final Widget child;

  ScopedModel({@required this.model, @required this.child})
      : assert(model != null),
        assert(child != null);

  @override
  Widget build(BuildContext context) {
  ///The [animation] and [builder] arguments must not be null.
  /// 子类不能为空,否则在下面会抛出异常throw new ScopedModelError();
  /// 构建 _InheritedModel 这样就能解释为什么子类能够从父类中获取数据了
    return AnimatedBuilder(
      animation: model,
      builder: (context, _) => _InheritedModel<T>(model: model, child: child),
    );
  }

  ......

    if (widget == null) {
      /// 抛出异常
      throw new ScopedModelError();
    } else {
      return (widget as _InheritedModel<T>).model;
    }
  }
}
///小结:ScopedModel会构建_InheritedModel 小部件,这样实现数据的传递
_InheritedModel 源码分析
/// _InheritedModel 继承InheritedWidget
class _InheritedModel<T extends Model> extends InheritedWidget {
  final T model;
  final int version;

  _InheritedModel({Key key, Widget child, T model})
      : this.model = model,
        this.version = model._version,
        super(key: key, child: child);

  /// 当version 改变时 updata 更新
  @override
  bool updateShouldNotify(_InheritedModel<T> oldWidget) =>
      (oldWidget.version != version);
}

总结:在最外层创建一个model,返回一个_InheritedModel类型的widget,通过Inherited小部件向子类传递数据,同时通过观察者模式
通知所有的子类去刷新UI,达到以Model驱动UI的效果。

由于时间原因,写的没那么详细,请见谅,以后会追加使用的方法。