前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Flutter Provider-ProxyProvider源码解析

Flutter Provider-ProxyProvider源码解析

作者头像
用户4458175
发布2022-04-15 15:03:39
发布2022-04-15 15:03:39
67200
代码可运行
举报
文章被收录于专栏:andy的小窝andy的小窝
运行总次数:0
代码可运行

我们先来看下ProxyProvider的官方介绍

ProxyProvider 能够将多个 provider 的值聚合为一个新对象,将结果传递给 Provider。这个新对象会在其依赖的任意一个 provider 更新后同步更新。

ProxyProvider跟Selector类似,有ProxyProviderProxyProvider2ProxyProvider3,类名后的数字代表Provider的数量,对应的其他ProxyProvider还有ChangeNotifierProxyProvider、ListenableProxyProvider,同样也有ChangeNotifierProxyProvider2、ChangeNotifierProxyProvider3、ListenableProxyProvider2、ListenableProxyProvider3…等类。

一样看下Demo

代码语言:javascript
代码运行次数:0
运行
复制
Widget build(BuildContext context) {
  return MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (_) => Counter()),
      ProxyProvider<Counter, Translations>(
        update: (_, counter, __) => Translations(counter.value),
      ),
    ],
    child: Builder(
        builder: (context) {
          return Scaffold(
            body: Center(
              child: Consumer<Translations>(builder: (child, model, context) {
                return Text(model.title);
              }),
            ),
            floatingActionButton: FloatingActionButton(onPressed: () {
              context.read<Counter>().increment();
            }),
          );
        }
      ),
  );
}

class Translations {
  const Translations(this._value);

  final int _value;

  String get title => 'You clicked $_value times';
}

上面的例子中,Consumer监听Translations类型的Provider,在Counter调用notifyListeners时会通知Consumer刷新。但是Translations是一个普通类,我们一起看下内部怎么实现转换的吧。

ProxyProvider继承自ProxyProvider0,需要实现update方法,传递update方法使用Provider.of(context)建立监听,ProxyProvider0继承InheritedProvider(在《Flutter Provider状态管理源码解析》文章已经介绍过建议配合使用哦,不过那时我们关注create方法,省略了一些update代码)。ProxyProvider实际是将转换后的状态类Translations作为InhritedWidget,Consumer与其建立联系监听。那ProxyProvider怎么与依赖的状态类Counter关联呢。我们接着看。

代码语言:javascript
代码运行次数:0
运行
复制
class ProxyProvider<T, R> extends ProxyProvider0<R> {
  /// Initializes [key] for subclasses.
  ProxyProvider({
    Key? key,
    Create<R>? create,
    required ProxyProviderBuilder<T, R> update,
    UpdateShouldNotify<R>? updateShouldNotify,
    Dispose<R>? dispose,
    bool? lazy,
    TransitionBuilder? builder,
    Widget? child,
  }) : super(
          key: key,
          lazy: lazy,
          builder: builder,
          create: create,
          update: (context, value) => update(
            context,
            Provider.of(context),
            value,
          ),
          updateShouldNotify: updateShouldNotify,
          dispose: dispose,
          child: child,
        );
}
代码语言:javascript
代码运行次数:0
运行
复制
class ProxyProvider0<R> extends InheritedProvider<R> {
  /// Initializes [key] for subclasses.
  ProxyProvider0({
    Key? key,
    Create<R>? create,
    required R Function(BuildContext context, R? value) update,
    UpdateShouldNotify<R>? updateShouldNotify,
    Dispose<R>? dispose,
    bool? lazy,
    TransitionBuilder? builder,
    Widget? child,
  }) : super(
          key: key,
          lazy: lazy,
          builder: builder,
          create: create,
          update: update,
          dispose: dispose,
          updateShouldNotify: updateShouldNotify,
          debugCheckInvalidValueType: kReleaseMode
              ? null
              : (R value) =>
                  Provider.debugCheckInvalidValueType?.call<R>(value),
          child: child,
        );
}

InheritedProvider会创建_delegate_CreateInheritedProvider是_delegate的create实现,会要求create != null || update != null,在获取value时候会调用update初始化value(如果是ChangeNotifierProxyProvider会有create过程和监听),这里的startListening是无效的因为我们是用的ProxyProvider类型,没有startListening方法。那是怎么实现自动更新呢?答案就是Counter类,我们Counter是一个ChangeNotifier,还记得上面ProxyProvider用了Provider.of(context),在Counter调用notifyListeners后,会触发_InheritedProviderScopeElement的build。

代码语言:javascript
代码运行次数:0
运行
复制
class _CreateInheritedProviderState<T>
    extends _DelegateState<T, _CreateInheritedProvider<T>> {
  VoidCallback? _removeListener;
  bool _didInitValue = false;
  T? _value;
  _CreateInheritedProvider<T>? _previousWidget;
  FlutterErrorDetails? _initError;

  @override
  T get value {
    if (_didInitValue && _initError != null) {
     ...
    if (!_didInitValue) {
      _didInitValue = true;
      if (delegate.create != null) {
        ...
      }
      if (delegate.update != null) {
        ...
        _value = delegate.update!(element!, _value);
        ...
      }
    }

    element!._isNotifyDependentsEnabled = false;
    _removeListener ??= delegate.startListening?.call(element!, _value as T);
    element!._isNotifyDependentsEnabled = true;
    assert(delegate.startListening == null || _removeListener != null);
    return _value as T;
  }

  @override
  void dispose() {
    super.dispose();
    _removeListener?.call();
    if (_didInitValue) {
      delegate.dispose?.call(element!, _value as T);
    }
  }

  @override
  void build({required bool isBuildFromExternalSources}) {
    var shouldNotify = false;
    // Don't call `update` unless the build was triggered from `updated`/`didChangeDependencies`
    // otherwise `markNeedsNotifyDependents` will trigger unnecessary `update` calls
    if (isBuildFromExternalSources &&
        _didInitValue &&
        delegate.update != null) {
      ...
        /// 更新依赖
        _value = delegate.update!(element!, _value as T);
      ...
    if (shouldNotify) {
      element!._shouldNotifyDependents = true;
    }
    _previousWidget = delegate;
    return super.build(isBuildFromExternalSources: isBuildFromExternalSources);
  }
}

_InheritedProviderScopeElement的build会触发_delegateState.build,build方法调用delegate.update!(element!, _value as T)更新数据。

代码语言:javascript
代码运行次数:0
运行
复制
class _InheritedProviderScopeElement<T> extends InheritedElement
    implements InheritedContext<T> {
  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
      : super(widget);

  static int _nextProviderId = 0;

  bool _shouldNotifyDependents = false;
  bool _debugInheritLocked = false;
  bool _isNotifyDependentsEnabled = true;
  bool _firstBuild = true;
  bool _updatedShouldNotify = false;
  bool _isBuildFromExternalSources = false;
  late _DelegateState<T, _Delegate<T>> _delegateState;
  late String _debugId;

  ...
  @override
  void didChangeDependencies() {
    _isBuildFromExternalSources = true;
    super.didChangeDependencies();
  }

  @override
  Widget build() {
    if (widget.owner._lazy == false) {
      value; // this will force the value to be computed.
    }
    _delegateState.build(
      isBuildFromExternalSources: _isBuildFromExternalSources,
    );
    _isBuildFromExternalSources = false;
    if (_shouldNotifyDependents) {
      _shouldNotifyDependents = false;
      notifyClients(widget);
    }
    return super.build();
  }

  ...
}

总结下,以上就是ProxyProvider实现原理啦,实际使用中ProxyProvider代理对象一般是ChangeNotifierProvider,由ChangeNotifierProvider触发更新。ChangeNotifierProxyProvider与ProxyProvider类似,ChangeNotifierProxyProvider需要实现createupdate方法,可以自己触发更新。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年4月14日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档