Flutter 自定义状态管理-BlocProvider(三种)

Bloc模式的出现, 主要用于分离UI组件和逻辑业务, 特别对于复杂的app状态管理, 能有效做到UI和业务解耦.

简单方法 Simple Bloc Provider

BlocProvider直接继承InheritedWidget, 这样其子Widget都能访问内部数据. 但是因为没有dispose方法,因此无法释放资源.


对于简单应用, 完全可以使用该方法而不必关心是否会浪费资源拖慢系统.

import 'package:flutter/material.dart';
import 'bloc_base.dart';

abstract class BlocBase {
  void dispose();
}

class BlocProvider<T extends BlocBase> extends InheritedWidget {
  final T bloc;
  final Widget child;
  BlocProvider({
    Key key,
    @required this.bloc,
    @required this.child,
  });

  static T of<T extends BlocBase>(BuildContext context) {
    BlocProvider<T> provider =
        context.inheritFromWidgetOfExactType(BlocProvider);
    return provider.bloc;
  }

  @override
  bool updateShouldNotify(BlocProvider<T> oldWidget) {
    return bloc != oldWidget.bloc;
  }
}

常规方法 Standard Bloc Provider

BlocProvider继承StatefulWidget, 可以确保在不需要的时候释放Bloc分配的资源.

这很好用但从性能角度来看并不是最佳的。
context.ancestorWidgetOfExactType()是一个为时间复杂度为O(n)的函数,为了检索某种类型的祖先,它将对widget树做向上导航,从上下文开始,一次递增一个父,直到完成。如果从上下文到祖先的距离很小(即O(n)结果很少),则可以接受对此函数的调用,否则应该避免。
Flutter - BLoC 第二讲 - 简书

import 'package:flutter/material.dart';
import 'bloc_base.dart';

abstract class BlocBase {
  void dispose();
}

class BlocProvider<T extends BlocBase> extends StatefulWidget {
  final T bloc;
  final Widget child;
  BlocProvider({Key key, @required this.bloc, @required this.child});

  static Type _typeOf<T>() => T;

  @override
  _BlocProviderState<T> createState() => _BlocProviderState<T>();

  static T of<T extends BlocBase>(BuildContext context) {
    final type = _typeOf<BlocProvider<T>>();
    BlocProvider<T> provider = context.ancestorWidgetOfExactType(type);
    return provider?.bloc;
  }
}

class _BlocProviderState<T extends BlocBase> extends State<BlocProvider<T>> {
  @override
  void dispose() {
    widget.bloc?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

复杂方法 Complex Bloc Provider

方法已来于StatefulWidget, 并结合InheritedWidget, 该方法的优点是性能好.

由于使用了InheritedWidget,它现在可以调用context.ancestorInheritedElementForWidgetOfExactType()函数,它是一个O(1),这意味着祖先的检索是立即的.
Flutter - BLoC 第二讲 - 简书

import 'package:flutter/material.dart';
import 'bloc_base.dart';

abstract class BlocBase {
  void dispose();
}

class BlocProvider<T extends BlocBase> extends StatefulWidget {
  final T bloc;
  final Widget child;
  BlocProvider({Key key, @required this.bloc, @required this.child})
      : super(key: key);

  static Type _typeOf<T>() => T;

  static T of<T extends BlocBase>(BuildContext context) {
    final type = _typeOf<_BlocProviderInherited<T>>();
    _BlocProviderInherited<T> provider =
        context.ancestorInheritedElementForWidgetOfExactType(type)?.widget;
    return provider?.bloc;
  }

  @override
  _BlocProviderState createState() => _BlocProviderState<T>();
}

class _BlocProviderState<T extends BlocBase> extends State<BlocProvider<T>> {
  /// 便于资源的释放
  @override
  void dispose() {
    widget.bloc?.dispose();
    super.dispose();
  }

  /// 返回继承了InheritedWidget的实例
  @override
  Widget build(BuildContext context) {
    return _BlocProviderInherited<T>(
      bloc: widget.bloc,
      child: widget.child,
    );
  }
}

class _BlocProviderInherited<T> extends InheritedWidget {
  final T bloc;
  final Widget child;
  _BlocProviderInherited({
    Key key,
    @required this.child,
    @required this.bloc,
  }) : super(key: key, child: child);

  @override
  bool updateShouldNotify(_BlocProviderInherited oldWidget) => false;
}

当然, pub上已经有不少的bloc插件, 轮子早有人造好了, 我们真正开发中能借用还是尽量借用. 但了解一些必要的原理还是很有必要的.

猜你喜欢

转载自blog.csdn.net/jdsjlzx/article/details/123410450