Flutter性能优化之局部刷新

Flutter中Widget分为StatefulWidget和StatelessWidget,分别为动态视图和静态视图,视图的更新需要调用StatefulWidget的setState方法,这会遍历调用子Widget的build方法。当一个主页面比较复杂时,会包含多个widget,如果直接调用setState,会遍历所有子Widget的build,这是非常不必要的性能开销,有没有单独刷新指定Widget的方式呢?这个时候就要用到GlobalKey了。

常规刷新Widget的方法

一个StatefulWidget包含一个Button,一个Text,通过点击Button调用主Widget的setState方法,刷新Text,示例如下:


3041564298371_.pic_hd.jpg
import 'package:flutter/material.dart';

class TestWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _TestWidgetState();
  }
}

class _TestWidgetState extends State<TestWidget> {
  int _count;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: <Widget>[
          Text((_count++).toString()),
          RaisedButton(
            onPressed: () {
              setState(() {
                _count++;
              });
            },
          )
        ],
      ),
    );
  }
}

通过GlobalKey局部刷新

同样一个StatefulWidget包含一个多个Text和Button,点击Button我们只需要刷新指定的Text,通过GlobalKey的方式,实现如下:


3051564298949_.pic_hd.jpg

主Widget,包含一个需要更新的TextWidget和一个不需要更新的Text

import 'package:cell_input/globalkey/button.dart';
import 'package:cell_input/globalkey/text.dart';
import 'package:flutter/material.dart';

class TestWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _TestWidgetState();
  }
}
class _TestWidgetState extends State<TestWidget> {
  int _count=0;
  GlobalKey<TextWidgetState> textKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          TextWidget(textKey),///需要更新的Text
          SizedBox(height: 20,),

          Text(_count.toString(),style: TextStyle(fontSize: 20),), ///这个Text不会刷新,只会刷新上面的TextWidget
         SizedBox(height: 20,),
          ButtonWidget(
            onPressed: () {
              ///点击button,调用TextWidget的onPressed方法
              ///在TextWidget的onPressed中单独调用TextWidget的setState,
              _count++;
              textKey.currentState.onPressed(_count);
            },
          )
        ],
      ),
    );
  }
}

需要单独更新的Widget

import 'package:flutter/material.dart';

class TextWidget extends StatefulWidget {
  TextWidget(Key key) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return TextWidgetState();
  }
}

class TextWidgetState extends State<TextWidget> {
  String _text="0";

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(_text,style: TextStyle(fontSize: 20),),
    );
  }

  void onPressed(int count) {
    setState(() {
      _text = count.toString();
    });
  }
}

传递事件的Button

import 'package:cell_input/globalkey/text.dart';
import 'package:flutter/material.dart';

typedef OnPressed();

class ButtonWidget extends StatefulWidget {
  OnPressed onPressed;

  ButtonWidget({this.onPressed});

  @override
  State<StatefulWidget> createState() {
    return _ButtonWidgetState(onPressed);
  }
}

class _ButtonWidgetState extends State<ButtonWidget> {
  OnPressed _onPressed;

  _ButtonWidgetState(this._onPressed);

  GlobalKey<TextWidgetState> key = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
        child: Text('count++',style: TextStyle(fontSize: 20),),
        onPressed: _onPressed,
      ),
    );
  }
}

这样点击Button就只会更新指定的TextWidget了,效果如下:


gifhome_320x640_7s.gif

这只是一个简单的例子,在实际开发中为了页面刷新的高效率,模块化封装非常重要。很多情况下都只需要局部刷新,而不是重构整个视图。所以Globalkey的运用在项目中需要熟练掌握
demo地址:https://github.com/po1arbear/cell_input-flutter/tree/master/lib/globalkey

推荐阅读更多精彩内容