前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter —— 状态管理 | ScopedModel

Flutter —— 状态管理 | ScopedModel

原创
作者头像
CatEatFish
修改2020-07-09 14:23:34
7590
修改2020-07-09 14:23:34
举报
文章被收录于专栏:干活分享干活分享

Flutter 无状态管理相当于 Androi 的mvc模式,数据UI写在一块,写起来简单,但是逻辑代码复杂,

不利于维护,接下来我会逐一解锁Flutter的状态管理。

Scoped Model介绍

Scoped Model 利用 model 的方式,轻松的将数据模型从父 Widget 传递到它的后代,并且此数据

模型实现观察者模式,当数据改变时,会通知实现的子类,重新构建新的子类 Widget 达到数据刷新的目的 。

代码语言:txt
复制
/// 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通知子类数据已经改变。

代码语言:txt
复制
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() {...}

源码分析

代码语言:txt
复制
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());
      });
    }
  }
}
代码语言:txt
复制
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 小部件,这样实现数据的传递
代码语言:txt
复制
_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的效果。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Scoped Model介绍
  • Scoped Model 原理
  • 源码分析
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档