flutter中的rebuild一些理解

在flutter中滥用statefulWidget将导致不可知的一些问题,其中一个问题就是会导致不停的rebuild整个页面,设想一下,你要是只需要点击一个按钮,更新一个按钮,却在点击这个按钮的时候,rebuild了整个页面,岂不是对性能的过大消耗?
为了解决这个问题,和直观的感觉这个问题,我引入了provider这个插件来作说明。
先上效果:

按第一个区域的按钮:

按第一个区域的按钮

按下第二个区域后再按下第三个区域:

按下第二个区域后再按下第三个区域

这里我用了三块区域来作说明:这三块区域都是使用的随机颜色,每次rebuild都会改变这些颜色。
首先,第一个区域是使用provider插件的,点击了按钮,counter会加1,但背景色没有做改变。
第二个区域使用的数据来自于最外面的statefulWidget,点击了按钮之后整个页面将会rebuild。
第三个区域是相当于一个叶子节点,它的counter数据来自于自己,点击按钮之后,这个区域会发生rebuild即只更新这个区域。
代码如下:

import 'dart:math';
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import 'models/counter.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => CounterModel(0)),
      ],
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Test()
      )
    );
  }
}

class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  // 这个counter将在第二区域中使用
  int counter = 0;

  _incrementCounter(){
    setState(() {
      ++counter;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Container(
          constraints: BoxConstraints.expand(),
          child: Column(
            children: <Widget>[
              Counter1(
                title: '使用provider不会触发rebuild'
              ),
              Counter2(
                counter: counter,
                onClick: _incrementCounter,
                title: '使用的是最外层的数据,改变会触发整个页面的rebuild',
              ),
              Counter3(
                title: '叶子节点,使用的自己内部的数据,自身rebuild不会影响外面',
              )
            ],
          ),
        ),
      ),
    );
  }
}
// 首先,第一个区域是使用provider插件的,点击了按钮,counter会加1,但背景色没有做改变
class Counter1 extends StatelessWidget {

  final counter;
  final title;
  Counter1({this.counter,this.title});
  BuildContext ctx;

  @override
  Widget build(BuildContext context) {
    ctx = context;
    Color color = Color.fromRGBO(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1);
    return Container(
      child: Consumer(builder: (BuildContext context, CounterModel counterModel, Widget child){
        return AnimatedContainer(
          duration: Duration(seconds: 1),
          color: color,
          height: 150,
          child: Column(
            children: <Widget>[
              Text(title,style: TextStyle(fontSize: 30)),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text('counter= ${counterModel.count}')
                ],
              ),
              RaisedButton(
                color: color,
                textColor: Colors.white,
                elevation: 20,
                child: Text('点我增加'),
                onPressed: _increment
              )
            ],
          ),
        );
      })
    );
  }

  void _increment() {
    Provider.of<CounterModel>(ctx,listen: false).increment();
    print(Provider.of<CounterModel>(ctx,listen: false).count);
  }
}
// 第二个区域使用的数据来自于最外面的statefulWidget,点击了按钮之后整个页面将会rebuild。
class Counter2 extends StatelessWidget {
  final VoidCallback onClick;
  final int counter;
  final String title;
  Counter2({
    Key key,
    this.counter,
    this.onClick,
    this.title
  });
  @override
  Widget build(BuildContext context) {
    Color color = Color.fromRGBO(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1);
    return AnimatedContainer(
      duration: Duration(milliseconds: 500),
      color:color,
      height: 250,
      child:Column(
        children: <Widget>[
          Text(title,style: TextStyle(fontSize: 30),),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('counter = ${this.counter}',style: TextStyle(fontSize: 43,color: Colors.white),),
            ],
          ),
          RaisedButton(
            color: color,
            textColor: Colors.white,
            elevation: 20,
            onPressed: onClick,
            child: Text('increment Counter'),
          ),
        ],
      ),
    );
  }
}
// 第三个区域是相当于一个叶子节点,它的counter数据来自于自己,点击按钮之后,这个区域会发生rebuild即只更新这个区域。
class Counter3 extends StatefulWidget {
  final title;
  Counter3({
    Key key,
    this.title
  }): super(key: key);

  @override
  _Counter3State createState() => _Counter3State();
}

class _Counter3State extends State<Counter3> {
  int counter = 0;
  @override
  Widget build(BuildContext context) {
    Color color = Color.fromRGBO(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1);
    return AnimatedContainer(
      duration: Duration(milliseconds: 500),
      color:color,
      height: 250,
      child:Column(
        children: <Widget>[
          Text(widget.title,style: TextStyle(fontSize: 30)),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('counter = $counter',style: TextStyle(fontSize: 43,color: Colors.white),),
            ],
          ),
          RaisedButton(
            color: color,
            textColor: Colors.white,
            elevation: 20,
            onPressed: _click,
            child: Text('increment Counter'),
          ),
        ],
      ),
    );
  }

  _click() {
    setState(() {
      ++counter;
    });
  }
}

复制代码

第一个区域中的model文件:

import 'package:flutter/material.dart';

class CounterModel with ChangeNotifier {
  int _count;
  CounterModel(this._count);
  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }

  void setValue(int val) {
    _count = val;
    notifyListeners();
  }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享