Provider 源碼走讀(從BlocProvider開始)

本篇基於分析代碼版本:緩存

flutter_bloc: v0.21.0markdown

provider: v3.1.0框架

BlocProvider

一、官方解釋功能:

It is used as a dependency injection (DI) widget so that a single instance of a bloc can be provided to multiple widgets within a subtree.ide

簡單說 BlocProvider 容許控件樹中的子控件可以獲取到同一個 bloc 實例。函數

BlocProvider示意圖

二、使用方法

// Father Widget
BlocProvider(
  builder: (BuildContext context) => BlocA(),
  child: ChildA(), 
);

// Child Widget
var blocA = BlocProvider.of<BlocA>(context);
複製代碼

三、代碼走讀:構造函數

首先看下 BlocProvider 的構造函數。ui

class BlocProvider<T extends Bloc<dynamic, dynamic>> extends Provider<T> {
  BlocProvider({
    Key key,
    @required ValueBuilder<T> builder,
    Widget child,
  }) : super(
          key: key,
          builder: builder,
          dispose: (_, bloc) => bloc?.dispose(),
          child: child,
        );

複製代碼

上面代碼裏去掉了註釋,而註釋對構造函數的功能有兩個信息點:this

  • 使用 ValueBuilder 構建 bloc 並提供給子節點獲取。spa

  • 自動處理了 bloc 的 dispose 工做。3d

因此咱們有了兩個疑問:代理

一、BlocProvider 如何可以提供給子節點提供 bloc ?

二、如何保障 bloc 單一實例,且能自動處理 bloc 的 dispose ?

答案須要從 BlocProvider 的父類 Provider 裏尋找。

Provider

provider

一、先看問題二:如何保障 bloc 單一實例,且能自動處理 bloc 的 dispose ?

答案在 BlocProvider 的父類 Provider 裏,咱們看下代碼

[./BlocProvider.dart]

class BlocProvider<T extends Bloc<dynamic, dynamic>> extends Provider<T> {
  BlocProvider({
    Key key,
    @required ValueBuilder<T> builder,
    Widget child,
  }) : super(
          key: key,
          builder: builder,
          dispose: (_, bloc) => bloc?.dispose(),
          child: child,
        );

複製代碼
  • 第 9 行,構造函數裏實現了一個 bloc dispose 的方法,並做爲父類構造函數的參數傳入。

[./provider.dart]

class Provider<T> extends ValueDelegateWidget<T> implements SingleChildCloneableWidget {
 
  Provider({
    Key key,
    @required ValueBuilder<T> builder,
    Disposer<T> dispose,
    Widget child,
  }) : this._(
          key: key,
          delegate: BuilderStateDelegate<T>(builder, dispose: dispose),
          updateShouldNotify: null,
          child: child,
        );

 Provider._({
    Key key,
    @required ValueStateDelegate<T> delegate,
    this.updateShouldNotify,
    this.child,
  }) : super(key: key, delegate: delegate);

}

複製代碼
  • BlocProvider(builder, child) 調用父類 Provider 的公開構造函數,再重定向到私有構造函數。

  • 第 10 行,將 BlocProvider 傳入的 bulder、dispose 方法包裝成 BuilderStateDelegate 代理對象。

  • 第 20 行,將這個代理做爲參數傳入父類 ValueDelegateWidget 的構造函數。

這裏的 BuilderStateDelegate 代理內部細節,咱們過會兒回來看。


二、BuilderStateDelegate 如何使用的?

繼續追溯父類,看看是如何使用這個代理 BuilderStateDelegate 的。

[/delegate_widget.dart]

abstract class ValueDelegateWidget<T> extends DelegateWidget {
  ValueDelegateWidget({
    Key key,
    @required ValueStateDelegate<T> delegate,
  }) : super(key: key, delegate: delegate);

  @override
  @protected
  ValueStateDelegate<T> get delegate => super.delegate as ValueStateDelegate<T>;
}
複製代碼
  • Provider 的父類是個抽象類 ValueDelegateWidget 代碼很簡單,支持使用的代理類型只有 ValueStateDelegate 。

  • 上一小節遺留的 BuilderStateDelegate 就是一種 ValueStateDelegate 的具體實現類。

[/delegate_widget.dart]

abstract class DelegateWidget extends StatefulWidget {
  const DelegateWidget({
    Key key,
    this.delegate,
  })  : assert(delegate != null),
        super(key: key);

  @protected
  final StateDelegate delegate;
  
  //...省略

  @override
  _DelegateWidgetState createState() => _DelegateWidgetState();
}

class _DelegateWidgetState extends State<DelegateWidget> {
  @override
  void initState() {
    super.initState();
    _mountDelegate();
    _initDelegate();
  }

  void _initDelegate() {
    // ... 省略斷言
    widget.delegate.initDelegate();
  }

  void _mountDelegate() {
    widget.delegate
      .._context = context
      .._setState = setState;
  }

  void _unmountDelegate(StateDelegate delegate) {
    delegate
      .._context = null
      .._setState = null;
  }

  @override
  void didUpdateWidget(DelegateWidget oldWidget) {
  // ... 省略
  }

  @override
  Widget build(BuildContext context) => widget.build(context);

  @override
  void dispose() {
    widget.delegate.dispose();
    _unmountDelegate(widget.delegate);
    super.dispose();
  }
}
複製代碼
  • DelegateWidget 就是一個 StatefulWidget 控件,代碼第 9 行,存儲了構造方法傳進來的代理 delegate。 而這個代理就是 Provider 裏的 BuilderStateDelegate

  • 代碼第 2二、52 行,分別調用了代理 delegateinitDelegate() dispose() 方法建立和銷燬 bloc。

小結下:

2-1. BlocProvider 構造函數參數一路傳遞的路徑以下:

起始:BlocProvider(ValueBuilder+Disposer)

--> Provider(BuilderStateDelegate)

--> ValueDelegateWidget(ValueStateDelegate)

--> DelegateWidget(StateDelegate) 成爲一個 StatefulWidget 的成員變量 delegate

2-2. BlocProvider 最終是繼承子一個 StatefulWidget, 並經過 Provider 生成一個 BuilderStateDelegate,最後傳入 delegateWidget。

2-3. 在這個 delegateWidget 的生命週期裏調用代理的初始化、更新、銷燬方法。


那具體到 BlocProvider 的 bloc 什麼時候建立和銷燬呢 ?

回到這個代理 BuilderStateDelegate 裏就有答案。


三、BuilderStateDelegate 源碼

[/delegate_widget.dart]

class BuilderStateDelegate<T> extends ValueStateDelegate<T> {
  /// The parameter `builder` must not be `null`.
  BuilderStateDelegate(this._builder, {Disposer<T> dispose})
      : assert(_builder != null),
        _dispose = dispose;

  final ValueBuilder<T> _builder;
  final Disposer<T> _dispose;

  T _value;
  @override
  T get value => _value;

  @override
  void initDelegate() {
    super.initDelegate();
    _value = _builder(context);
  }

  @override
  void didUpdateDelegate(BuilderStateDelegate<T> old) {
    super.didUpdateDelegate(old);
    _value = old.value;
  }

  @override
  void dispose() {
    _dispose?.call(context, value);
    super.dispose();
  }
}
複製代碼
  • 代碼第 3 行,接收來自 BlocProvider 傳遞過來的 ValueBuilder (用來建立 bloc 的一個方法對象)和 Disposer (用來銷燬 bloc 的一個方法對象)。

  • 代碼 11~12 行,存儲類型爲 T 的 _value 值,並提供 get 方法。

  • 代碼 1七、28 行,分別在 initDelegate()dispose() 裏,觸發傳進來的 _builder_dispose 方法,初始化了 _value 值(建立 bloc)、調用了 disposer 方法(銷燬 bloc)。

abstract class ValueStateDelegate<T> extends StateDelegate {
  /// The member [value] should not be mutated directly.
  T get value;
}
複製代碼
  • 其父類 ValueDelegate,內容比較簡單,擴展 StateDelegate 並增長存儲了 value。

[/delegate_widget.dart]

abstract class StateDelegate {
  BuildContext _context;

  BuildContext get context => _context;

  StateSetter _setState;

  @protected
  StateSetter get setState => _setState;

  @protected
  @mustCallSuper
  void initDelegate() {}

  @protected
  @mustCallSuper
  void didUpdateDelegate(covariant StateDelegate old) {}

  @protected
  @mustCallSuper
  void dispose() {}
}
複製代碼
  • 其父類 StateDelegate ,剔除註釋後比較直觀了,就是一個 State 生命週期回調的代理包裝。

小結:

BlocProvider(
  builder: (BuildContext context) => BlocA(),
  child: ChildA(), 
);
複製代碼

3-1. 父類 Provider 裏用 BuilderStateDelegate 代理包裝了 bloc 的初始化和銷燬方法。

3-2. BuilderStateDelegate 代理存儲了(_value)bloc 初始化方法的結果

3-3. Provider 最終繼承自 DelegateWidget,一個 StatefulWidget。在生命週期裏調用代理的一樣的方法。

3-4. 框架裏常見的代理模式,順着 BlocProvider 及其父類的構造函數看下來就比較清楚了。


四、再看問題一:如何存儲這個單一實例 bloc,並提供給子控件的?

// 子控件是如何經過下面這句獲取到 bloc 的 ?

var blocA = BlocProvider.of(context);

從上面的第 3 節,咱們知道代理裏面有咱們的且惟一的 bloc,存儲形式就是 _value

而 BlocProvider 繼承自 Provider,最終都是一個 StatefulWidget,咱們看看它的 build 方法有什麼特別的。

4-一、Provider build() 方法

class Provider<T> extends ValueDelegateWidget<T> implements SingleChildCloneableWidget {
 
  @override
  Widget build(BuildContext context) {
    //...省略斷言
    return InheritedProvider<T>(
      value: delegate.value,
      updateShouldNotify: updateShouldNotify,
      child: child,
    );
  }
複製代碼
  • 第 6 行,最終 build() 方法裏返回的是 InheritedProvider<T>

  • 第 7 行,給定的 value 就是代理 delegate的 value。

  • delegate 代理就是在構造函數建立的 BuilderStateDelegate ,包裝了 BlocProvider 傳入的 valueBuilderdispose() 方法。

  • 第 9 行,child 就是控件 BlocProvider 傳入的 child widget 。


4-二、InheritedProvider

[./provider.dart]

class InheritedProvider<T> extends InheritedWidget {

  const InheritedProvider({
    Key key,
    @required T value,
    UpdateShouldNotify<T> updateShouldNotify,
    Widget child,
  })  : _value = value,
        _updateShouldNotify = updateShouldNotify,
        super(key: key, child: child);
        
	final T _value;
	final UpdateShouldNotify<T> _updateShouldNotify;
	
	// ... 省略
}
複製代碼
  • InheritedProvider 其實就是一個 InheritedWidget 。

  • 構造函數傳入代理的值(delegate.value), 也被暫存爲成員變量 _value 。


4-三、BlocProvider.of(context)

[./bloc_provider.dart]

// BlocProvider.of<T>() 方法
 static T of<T extends Bloc<dynamic, dynamic>>(BuildContext context) {
    try {
      return Provider.of<T>(context, listen: false);
    } catch (_) {
    // ...
    }
複製代碼
  • BlocProvider.of<T> 其實調用的是 Provider 的 Provider.of<T> 方法 (listen 值爲 false)。

[./provider.dart]

/// Returns the type [T].
Type _typeOf<T>() => T;

// Provider.of<T>() 方法
static T of<T>(BuildContext context, {bool listen = true}) {
	// this is required to get generic Type
	final type = _typeOf<InheritedProvider<T>>();
	final provider = listen
	    ? context.inheritFromWidgetOfExactType(type) as InheritedProvider<T>
	    : context.ancestorInheritedElementForWidgetOfExactType(type)?.widget
	        as InheritedProvider<T>;
	
	// ... 省略異常檢查
	
	return provider._value;
}
複製代碼
  • 代碼第 8-11 行,listen 值爲false,觸發 context.ancestorInheritedElementForWidgetOfExactType(type) 方法找到 InheritedProvider<T> 類型的控件。

  • 代碼第 15 行,返回這個 InheritedProvider._value

  • 聯繫 4-2 小節,這個返回的就是 delegate.value, 也就是咱們在代理裏生成的 bloc 了。

by flutter_bloc 做者

爲何要用 ancestorInheritedElementForWidgetOfExactType 而不用 inheritFromWidgetOfExactType ?

由於 inheritFromWidgetOfExactType 不只查找獲取符合指定類型的Widget,還將context 註冊到該Widget,以便Widget發生變更後,context能夠獲取到新值;

這並非咱們想要的,咱們想要的僅僅就是符合指定類型的Widget(也就是 BlocProvider)而已。

本篇總結

至此咱們應該搞明白瞭如下幾點:

一、BlocProvider 構造函數傳入的參數被父類 Provider 控件包裝成代理 BuilderStateDelegate。而 Provider 本質是一個 StatefulWidget 控件,在其 State 的生命週期裏,觸發代理的相對應回調。

二、BuilderStateDelegate 代理能夠感知 StatefulWidget 的生命週期,在適當時候,建立、保存和銷燬惟一的 _value值(就是咱們的 bloc)。

三、Provider 在 build() 方法裏,返回了一個 InheritedProvider,傳入了代理的 _value值。 它本質是 InheitedWidget 類型的控件。

四、經過 BlocProvider.of(context) 獲取到 bloc ,實際上是經過 context.ancestorInheritedElementForWidgetOfExactType(type) 獲取到 InheritedProvider,取出裏面的 _value值。

如今回過來看這幾個控件的繼承關係圖,是否是更清楚了呢?

provider

備註:

一、RepositoryProvider 代碼相似,再也不贅述。

二、context.ancestorInheritedElementForWidgetOfExactType(type) 如何獲取到 type 類型的 widget ?( Map<Type, InheritedElement> _inheritedWidgets 緩存 ) 後續再講。

相關文章
相關標籤/搜索