Flutter用状态管理起源类InheritedWidget来定义自己的provider

提笔缘由

状况办理伴随着Flutter的开展日益丰厚,如果说响应式是Flutter的特色,那么状况办理的便是完结办法,从开始的provide再到官方认可的provider,还有scoped_model,event_bus,get,riverpod,BloC,redux等等太多。作为开发者,对这些状况办理完结办法能够了解一二,当然由于学疏才浅,我只能略懂。Stream和InheritedWidget两种不同办法完结状况办理,项目中常用的Provider中心便是InheritedWidget,所以经过探究该类来旁边面了解provider,在实践中很少用到InheritedWidget,但他是个幕后英雄。

关联知识点

  • InheritedWidget
  • ValueNotifier
  • ValueListenBuilder
  • Builder
  • ChangeNotifier
  • ValueListenable

类InheritedWidget

结构函数很简略,需求必传一个Widget,由于只有他的child,才能获取到寄存在树梢的数据。

InheritedWidget({Key key,required Widget child})

承继InheritedWidget后有必要override的办法,作用是你来决定通知改变的条件,以便节约资源。

updateShouldNotify(
covariant InheritedWidget oldWidget
) → bool

承继的新类需求一个静态办法 of(context),也是中心的一步,child便是经过of获取在树梢的数据,凭借context.dependOnInheritedWidgetOfExactType办法来获取。

最简略示例

用最简略的比如演示InheritedWidget运用过程,界说类ColorInherited承继InheritedWidget,里边寄存颜色color和巨细size,ColorInherited用于下面的child获取。ColorInherited能够放在Scaffold上下都能够,留意点是需求类Builder促使生成context,否则会由于context问题而报错,第二个留意点是dependOnInheritedWidgetOfExactType办法是泛型,要传入详细类。示例代码如下:

import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: ColorInheritedPage()));
class ColorInheritedPage extends StatelessWidget {
  const ColorInheritedPage({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('InheritedWidget演示')),
      body: ColorInherited(
        size: const Size(300, 100),
        color: Colors.brown,
        child: Builder(builder: (context) {
          var provider = ColorInherited.of(context);
          return Container(
            height: provider.size.height,
            width: provider.size.width,
            color: provider.color,
          );
        }),
      ),
    );
  }
}
class ColorInherited extends InheritedWidget {
  final Color color;
  final Size size;
  const ColorInherited({
    super.key,
    required super.child,
    required this.color,
    required this.size,
  });
  static ColorInherited of(BuildContext context) {
    var inherited = context.dependOnInheritedWidgetOfExactType<ColorInherited>();
    assert(inherited != null, 'error:No ColorInherited ');
    return inherited!;
  }
  @override
  bool updateShouldNotify(covariant ColorInherited oldWidget) {
    return oldWidget.size != size || oldWidget.color != color;
  }
}

计数器示例

在了解InheritedWidget如何运用后,咱们可继续探究。上面比如中是静态数据,页面没有任何改变,现在用他来做个计数器的页面,是一种有改变的状况,需求及时去响应,就能够结合ChangeNotifier类,这个是不是了解的味道,在provider中界说数据类时需求承继他,凭借ChangeNotifier界说自己的数据,寄存一个变量,是需求ValueNotifier类,

//寄存需求监听的变量
class CounterNotify extends ChangeNotifier {
  final countState = ValueNotifier<int>(0);
  void add() => countState.value++;
}

而ValueListenableBuilder担任在页面上响应改变做到部分改写,ValueNotifier和ValueListenableBuilder配套运用。

有数据源之后,需求凭借InheritedWidget来放在树上,其下child随时取用,这个状况办理类CounterInherited里有个变量是CounterNotify类型的,也便是数据源。

//类似于Provider类
class CounterInherited extends InheritedWidget {
  const CounterInherited({
    super.key,
    required super.child,
    required this.counterNotify,
  });
  final CounterNotify counterNotify;
  static CounterInherited of(BuildContext context) {
    var inherited = context.dependOnInheritedWidgetOfExactType<CounterInherited>();
    assert(inherited != null, '在context中未找到CounterInherited类');
    return inherited!;
  }
  @override
  bool updateShouldNotify(covariant CounterInherited oldWidget) {
    return oldWidget.counterNotify != counterNotify;
  }
}

万事具备,只欠显现在页面上,ValueNotifier和ValueListenableBuilder配套运用,一个担任页面端显现,一个担任状况改变及通知。其实更严格地说是ValueListenable和ValueListenableBuilder配套运用,ValueNotifier只是抽象类ValueListenable的承继者,还有了解的类Animation也是属于ValueListenable,

//结构函数
ValueListenableBuilder({
Key? key, 
required ValueListenable<T> valueListenable, //对应数据源的变量
required ValueWidgetBuilder<T> builder, 
Widget? child
})
//抽象类ValueListenable的承继者有: ValueNotifier、Animation、RouteInformationProvider、SelectionHandler。

用InheritedWidget和ValueListenable组装的计数器完结,代码如下:

//空安全,Flutter3.3.2
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: CounterInheritedPage()));
class CounterInheritedPage extends StatelessWidget {
  const CounterInheritedPage({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return CounterInherited(
      counterNotify: CounterNotify(),
      child: Scaffold(
        appBar: AppBar(title: const Text('InheritedWidget计数器')),
        //需求Builder促使context实例,否则无context
        body: Builder(builder: (context) {
          var provider = CounterInherited.of(context).counterNotify;
          return Center(
            child: GestureDetector(
              onTap: provider.add,
              //部分改写
              child: ValueListenableBuilder(
                valueListenable: provider.countState,
                builder: (context, value, child) {
                  return Text('${provider.countState.value}');
                },
              ),
            ),
          );
        }),
      ),
    );
  }
}
//类似于Provider类
class CounterInherited extends InheritedWidget {
  const CounterInherited({
    super.key,
    required super.child,
    required this.counterNotify,
  });
  final CounterNotify counterNotify;
  static CounterInherited of(BuildContext context) {
    var inherited = context.dependOnInheritedWidgetOfExactType<CounterInherited>();
    assert(inherited != null, '在context中未找到CounterInherited类');
    return inherited!;
  }
  @override
  bool updateShouldNotify(covariant CounterInherited oldWidget) {
    return oldWidget.counterNotify != counterNotify;
  }
}
//寄存需求监听的变量
class CounterNotify extends ChangeNotifier {
  final countState = ValueNotifier<int>(0);
  void add() => countState.value++;
}