前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter状态管理(1)——InheritedWidget

Flutter状态管理(1)——InheritedWidget

作者头像
用户1108631
发布2019-09-17 14:09:17
1.2K0
发布2019-09-17 14:09:17
举报

状态管理

Flutter的状态管理分为两种:局部状态和全局状态。

局部状态:根据官方的含义,就是一个StatefulWidget可以搞定的,比如BottomNavigationBar、PageView等等,其他Widget不需要知道你的状态,你也不需要依赖其他Widget的状态;setState可以实现状态的切换; 全局状态:整个app很多页面都需要用到的状态,比如是否登录了,用户名、用户id等;这个的实现有很多方式,可以参考List of state management approaches

局部状态和全局状态的划分可以参考下图:

Flutter状态管理系列主要指的是全局状态的管理,主要介绍的几种实现方式有:

  • InheritedWidget
  • StreamBuilder
  • Provider

前两种,框架自带;第三种是google推荐使用的三方库。 本文将首先介绍InheritedWidget的实现方式。

InheritedWidget实现全局状态的管理

Flutter数据传输中,介绍了数据从上向下的传输方式,其中介绍了InheritedWidget的使用,当时的例子是在一个page里面,数据从上向下传输,不熟悉的朋友可以先去看下那篇文章。

这里,将使用InheritedWidget作为全局状态的管理者,那么将InheritedWidget作为根Widget可以实现下面的Widget都可以获取到该Widget持有的状态。

下面的例子,涉及两个页面,第一个页面展示是否登录信息,第二个页面根据是否登录了来走是登录、还是退出的逻辑。

实现

Step1:状态类的定义

代码语言:javascript
复制
class LoginState {
  bool isLogin = false;

  @override
  bool operator ==(other) {
    return isLogin == (other as LoginState).isLogin;
  }
}

这边比较简单,定义了一个LoginState,isLogin表示是否登录的状态。

重写了==,isLogin状态不变,可以认为LoginState没有变化。

Step2:InheritedWidget的定义

代码语言:javascript
复制
class LoginStateWidget extends InheritedWidget {
  const LoginStateWidget({Key key, this.loginState, Widget child})
      : super(key: key, child: child);

  static LoginStateWidget of(BuildContext context) {
    return context.inheritFromWidgetOfExactType(LoginStateWidget);
  }

  final LoginState loginState;

  @override
  bool updateShouldNotify(LoginStateWidget oldWidget) {
    return oldWidget.loginState == this.loginState;
  }
}

InheritedWidget持有LoginState对象;另外需要提供of静态方法,方法实现是context.inheritedFromWidgetOfExactType;updateShouldNotify方法是用来判断当该Widget变化时,这里面如果LoginState变化了,即isLogin参数变化了,才会去通知那些依赖该Widget的Widget变化。

Step3:根Widget使用

代码语言:javascript
复制
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return LoginStateWidget(
      child: MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: Text('状态管理'),
          ),
          body: MainPage(),
        ),
      ),
      loginState: LoginState(),
    );
  }
}

可以看到,在MaterialApp外面套了一层LoginStateWidget,并且传入了一个初始的LoginState。

Step4:子Widget获取状态

获取的方式是:

代码语言:javascript
复制
LoginStateWidget loginStateWidget=LoginStateWidget.of(context);

拿到了Widget之后,就可以拿到LoginState进行操作了。

主页面的代码如下:

代码语言:javascript
复制
class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    LoginState loginState = LoginStateWidget.of(context).loginState;
    return Container(
      child: Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) {
              return LoginPage();
            }));
          },
          child: Text(loginState.isLogin ? '已登录' : '未登录'),
        ),
      ),
    );
  }
}

这里Text会根据登录状态实行文字切换,但是依然声明的是一个StatelessWidget。

LoginPage的代码如下,和MainPage差距不大:

代码语言:javascript
复制
class LoginPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    LoginState loginState = LoginStateWidget.of(context).loginState;

    return Scaffold(
      appBar: AppBar(
        title: Text('登录页面'),
      ),
      body: Container(
        child: Center(
          child: RaisedButton(
            onPressed: () {
              loginState.isLogin = !loginState.isLogin;
              Navigator.of(context).pop();
            },
            child: Text(loginState.isLogin ? '退出登录' : '登录'),
          ),
        ),
      ),
    );
  }
}

运行效果

InheritedWidget的问题

这里我们只有一个状态,试想,如果有多个全局状态,那么应该怎么实现?

  1. 一个InheritedWidget,多个表示状态的类;需要考虑InheritedWidget的updateShouldNotify方法需要如何实现,每个状态稍有不同就去通知,那么全局那么多Widget都会收到消息,而更多的Widget只是关注某一状态,是否会造成性能损失?
  2. 多个InheritedWidget,每个InheritedWidget管理一个状态类,这个时候需要嵌套InheritedWidget,如果每个状态之间还有依赖的话,还需要考虑InheritedWidget的嵌套顺序

上面两种方案,是我目前能想到的两种方案,可以看到,都有各种各样的问题。

原理

关于InheritedWidget的实现原理,可以参考从 Flutter 源码看 InheritedWidget 内部实现原理

总结

可以发现InheritedWidget的使用,可以看做是在全局创建InheritedWidget及其管理的状态,然后所有的子Widget都可以获取到该对象及其状态,然后每个可以获取的Widget即是Producer又是Consumer,一切操作就是操作对象一样更改状态,剩下的系统会帮你做掉。

参考

  • Differentiate between ephemeral state and app state
  • List of state management approaches
  • 从 Flutter 源码看 InheritedWidget 内部实现原理
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 每天学点Android知识 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 状态管理
  • InheritedWidget实现全局状态的管理
    • 实现
      • Step1:状态类的定义
      • Step2:InheritedWidget的定义
      • Step3:根Widget使用
      • Step4:子Widget获取状态
      • 运行效果
      • InheritedWidget的问题
  • 原理
  • 总结
  • 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档