Flutter 局部刷新/ 状态管理

举报
坚果的博客 发表于 2022/03/31 21:56:38 2022/03/31
【摘要】 Flutter 局部刷新/ 状态管理在Flutter中,如果我们想要更新页面中的某个widget的状态的话,一般会使用setState方法重走build方法来刷新。//Flutter是描述性的(declarative), UI反映状态.​UI = f(state)​当页面布局复杂的时候,这样肯定是不行的。 这边梳理了下几种常见的方式,做个记录,方便将来选型总体分为两类:第一类,Dart 和 ...

Flutter 局部刷新/ 状态管理

在Flutter中,如果我们想要更新页面中的某个widget的状态的话,一般会使用setState方法重走build方法来刷新。

//Flutter是描述性的(declarative), UI反映状态.
​
UI = f(state)
​

当页面布局复杂的时候,这样肯定是不行的。 这边梳理了下几种常见的方式,做个记录,方便将来选型

总体分为两类:

第一类,Dart 和 Flutter 内置支持

1. setState.

Flutter里面最重要的方式 setState,规模较小的程序足够了,所有其它方式最终都需要调用 setState。

setState((){ 
  _value = "new data"; 
}); 
​

2. Function callback, 主要的实现有: ChangeNotifier, ValueNotifier

ValueNotifier 里面包含一个 T value 值,当值改变的时候,会通知它的监听来刷新UI

ValueListenableBuilder需要的元素:

  • 类型为 ValueWidgetBuilder<T> 的 builder, 监听对象的界面展现. 本质是一个方法,Widget Function(BuildContext context, T value, Widget child)

  • ValueListenable<T> 对象 , 监听对象, 这里用它的实现类: ValueNotifier

使用

//初始化
  ValueNotifier<int> indexNotifier = ValueNotifier(0);
//数据变更:
indexNotifier.value = value;
//触发UI刷新
 ValueListenableBuilder(
            valueListenable: indexNotifier,
            builder: (BuildContext context, int value, Widget child) {
              return CircleCheckBox(
                size: 40,
                activeColor: Color(periwinkle),
                value: _isSelect(value),
                onChanged: _onSelect,
              );
            },
          )
​
//销毁
    indexNotifier.dispose();
​
​

ValueNofiter 其实跟Android DataBinding 里面的 ObserverField 类似,都是使用一个观察者模式来实现数据驱动UI修改。

使用过程发现,这个类有个bug 当Value 是List是使用,修改数据不会发出通知,需要手动调用 notifyLisener().

3. Global Key通信

GlobalKey能够跨Widget访问状态,相比于Flutter的 函数声明式编程 类似 android等其他平台的命令式调用

//初始化:
​
GlobalKey<SwitcherWidgetState> key = GlobalKey();
​
//使用:
          key.currentState.changeState();
​
​

4. StreamBuilder

StreamBuilder也是官方内置的一种刷新UI方式。数据封装成 通知UI变更

 //步骤1:初始化一个StreamController<可以是 int string...  一般是model> 
  final StreamController<String> _streamController = StreamController<String>();
​
 //发送
 _streamController.sink.add(_str);
 
 //UI 变更
         child: StreamBuilder<String>(  // 监听Stream,每次值改变的时候,更新Text中的内容
          stream: _streamController.stream,
          initialData: _str,
          builder: (BuildContext context, AsyncSnapshot<int> snapshot){
            return Text('点击的时候这个值会改变: ${snapshot.data}');
          }
        ),
​
 // 销毁
    _streamController.close();
​
​

5. FutureBuilder

通常用于是 异步编程,Future返回值是情况,它的构造方法:

const FutureBuilder({
    Key key,
    this.future,          //获取数据的方法
    this.initialData,   //初始的默认数据
    @required this.builder
  }) : assert(builder != null),
       super(key: key);
​

第二类,包-外部实现

1. provider

实现:

  • model类继承ChangeNotifer,

class CounterModel extends ChangeNotifier {
  int value = 0;
​
  void increment() {
    value++;
    notifyListeners();
  }
​
  void decrement() {
    value--;
    notifyListeners();
  }
}
​
  • 数据提供者: ChangeNotifierProvider

void main() => runApp(ChangeNotifierProvider(
      create: (context) => CounterModel(),
      child: MyApp(),
    ));
​
  • 数据消费者/操纵者, 有两种方式: Consumer包裹, 用Provider.of.

  Consumer<CounterModel>(
    builder: (context, counter, child) => Text(
      '${counter.value}',
    ),
  ),

或者:

 FloatingActionButton(
    onPressed: () =>
        Provider.of<CounterModel>(context, listen: false).increment(),
  ),

Provider性能相关的实现细节

  • Consumer包裹的范围要尽量小.

  • Consumer中builder方法的第三个参数child 可以用于缓存一些并不需要重建的widget:

return Consumer<CartModel>(
  builder: (context, cart, child) => Stack(
        children: [
          // Use SomeExpensiveWidget here, without rebuilding every time.
          child,
          Text("Total price: ${cart.totalPrice}"),
        ],
      ),
  // Build the expensive widget here.
  child: SomeExpensiveWidget(),
);
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。