Flutter —— 狀態(tài)管理 | ScopedModel

Flutter 無狀態(tài)管理相當(dāng)于 Androi 的mvc模式,數(shù)據(jù)UI寫在一塊,寫起來簡單,但是邏輯代碼復(fù)雜,
不利于維護,接下來我會逐一解鎖Flutter的狀態(tài)管理。

Scoped Model介紹

Scoped Model 利用 model 的方式,輕松的將數(shù)據(jù)模型從父 Widget 傳遞到它的后代,并且此數(shù)據(jù)
模型實現(xiàn)觀察者模式,當(dāng)數(shù)據(jù)改變時,會通知實現(xiàn)的子類,重新構(gòu)建新的子類 Widget 達到數(shù)據(jù)刷新的目的 。

/// 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 中實現(xiàn)了抽象方法,Listenable中體現(xiàn)了注冊監(jiān)聽,notifyListener通知子類數(shù)據(jù)已經(jīng)改變。

abstract class Model extends Listenable

///注冊監(jiān)聽
/// Register a closure to be called when the object notifies its listeners.
void addListener(VoidCallback listener);

///刪除監(jiān)聽
/// Remove a previously registered closure from the list of closures that the
/// object notifies.
void removeListener(VoidCallback listener);

///通知監(jiān)聽者
@protected
void notifyListeners() {...}

源碼分析

Model源碼分析

abstract class Model extends Listenable {
  //創(chuàng)建一個監(jiān)聽的回調(diào)集合
  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++;
      //調(diào)用消息隊列
      scheduleMicrotask(() {
        //_version 改變會通知子類數(shù)據(jù)已改變,在_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!
        //執(zhí)行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();
  /// 構(gòu)建 _InheritedModel 這樣就能解釋為什么子類能夠從父類中獲取數(shù)據(jù)了
    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;
    }
  }
}
///小結(jié):ScopedModel會構(gòu)建_InheritedModel 小部件,這樣實現(xiàn)數(shù)據(jù)的傳遞
_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);

  /// 當(dāng)version 改變時 updata 更新
  @override
  bool updateShouldNotify(_InheritedModel<T> oldWidget) =>
      (oldWidget.version != version);
}

總結(jié):在最外層創(chuàng)建一個model,返回一個_InheritedModel類型的widget,通過Inherited小部件向子類傳遞數(shù)據(jù),同時通過觀察者模式
通知所有的子類去刷新UI,達到以Model驅(qū)動UI的效果。

由于時間原因,寫的沒那么詳細,請見諒,以后會追加使用的方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容