使用 setState() 时,Flutter 使屏幕闪烁蓝色

Flutter flashes screen light blue when using setState()

好的,找了半天没找到。这个问题似乎是构建缓存的问题,但我找不到有关清除构建缓存的资源,也找不到有关如何解决此特定问题的任何资源。

我的代码如下:

part of finance_app;

class InvestmentDetail extends StatefulWidget {
  final String userEmail;
  final String userName;
  final String profilePic;
  final String providerID;
  final String uid;
  InvestmentDetail(
      {@required this.userEmail,
      @required this.userName,
      @required this.profilePic,
      @required this.providerID,
      @required this.uid});
  @override
  _InvestmentDetailState createState() => _InvestmentDetailState();
}

final FirebaseAuth _auth = FirebaseAuth.instance;

class _InvestmentDetailState extends State<InvestmentDetail>
    with SingleTickerProviderStateMixin {
  bool firstRun = true;
  bool showMoney = true;
  bool readyToShowChart = false;
  var refreshkey = GlobalKey<RefreshIndicatorState>();
  LineChart chart;
  bool isTapped = false;
  Future<String> displayName() async {
    FirebaseUser _user = await FirebaseAuth.instance.currentUser();
    return _user.displayName;
  }

// various other functions go here

  void createLine2() {
    print("working");
    Firestore.instance
        .collection("user/" + widget.userEmail + "/investmentHistory")
        .snapshots()
        .listen(
          (data) => {
            print(data),
            line1 = {},
            data.documents.forEach(
              (doc) => {
                print(doc["percentage"]),
                line1[DateTime.fromMillisecondsSinceEpoch(
                    int.parse(doc.documentID).round())] = doc["percentage"],
              },
            ),
            chart = !f.format(percentageChangeTotal).contains("-")
                ? LineChart.fromDateTimeMaps(
                    [line1], [Colors.red], ['%'],
                  )
                : LineChart.fromDateTimeMaps(
                    [line1], [Colors.green], ['%'],
                  ),
          },
        );
  }
  @override
  void dispose() {
    super.dispose();
  }

  @override
  void initState() {
    createLine2();
    super.initState();
  }


  
  @override
  Widget build(BuildContext context) {
    createLine2();
    return WillPopScope(
      onWillPop: () async => false,
      child: Scaffold(
        body: SafeArea(
          child: Column(
            children: <Widget>[
              Expanded(
                child: StreamBuilder<QuerySnapshot>(
                  stream: Firestore.instance
                      .collection(
                          'user/' + widget.userEmail + '/positionLabels')
                      .orderBy("Date", descending: true)
                      .orderBy("Time", descending: true)
                      .snapshots(),
                  builder: (BuildContext context,
                      AsyncSnapshot<QuerySnapshot> snapshot) {
                    if (snapshot.hasError) {
                      return new Text('Error: ${snapshot.error}');
                    }
                    if (!snapshot.hasData) {
                      return Padding(
                        padding: const EdgeInsets.all(50.0),
                        child: Center(
                          child: Text(
                            "Add your first transaction!\n\nTap your profile picture in the top right to add your first order",
                            style: TextStyle(color: Colors.white),
                            textAlign: TextAlign.center,
                          ),
                        ),
                      );
                    } else {
                      switch (snapshot.connectionState) {
                        case ConnectionState.none:
                          print("ConnectionState: NONE");
                          return Text(
                            'Select',
                            style: TextStyle(color: Colors.white),
                          );
                        case ConnectionState.waiting:
                          print("ConnectionState: WAITING");
                          return LinearProgressIndicator();
                        case ConnectionState.done:
                          print("ConnectionState: DONE");
                          return Text(
                            '$${snapshot.data} (closed)',
                            style: TextStyle(color: Colors.white),
                          );
                        default:
                          return Column(
                            children: <Widget>[
                              SearchBar(
                                  widget: widget,
                                  nodeOne: nodeOne,
                                  controller: controller),
                              GestureDetector(
                                onTap: () {
                                  setState(() {
                                    readyToShowChart = true;
                                  });
                                },
                                child: Column(
                                  children: <Widget>[
                                    Container(
                                      padding: EdgeInsets.only(
                                          top: 20,
                                          right: 10,
                                          left: 10,
                                          bottom: 5),
                                      height: 200,
                                      width: MediaQuery.of(context).size.width,
                                      child: AnimatedOpacity(
                                        duration: Duration(seconds: 2),
                                        opacity: readyToShowChart ? 1 : 0,
                                        child: AnimatedLineChart(
                                          chart,
                                          key: UniqueKey(),
                                        ),
                                      ),
                                    ),
                                    TotalPositionsWidget(
                                        f.format(
                                            getTotalMoneySpent(snapshot.data)),
                                        getTotalAccountValue(snapshot.data)),
                                    PositionsChangeWidget(
                                        workWithNumbers(snapshot.data),
                                        f.format(percentageChangeTotal)),
                                  ],
                                ),
                              ),
                              Expanded(
                                child: RefreshIndicator(
                                  color: Colors.white,
                                  onRefresh: () => refreshMain(snapshot.data),
                                  key: refreshkey,
                                  child: ListView(
                                    children: snapshot.data.documents.map(
                                      (DocumentSnapshot document) {
                                        return new AnimatedOpacity(
                                          opacity: 1.0,
                                          duration:
                                              Duration(milliseconds: 1000),
                                          child: StockListTile(
                                              document, widget.userEmail),
                                        );
                                      },
                                    ).toList(),
                                  ),
                                ),
                              ),
                            ],
                          );
                      }
                    }
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

为简化起见:我有一个 StreamBuilder,它有一个列作为其子项。该列包含:

当我点击文本小部件并触发“setState”时,屏幕在执行命令之前闪烁淡蓝色:

tapping the Text widget three times

看来 Flutter 正在重建整个布局。

一个较小的附带问题(虽然不像闪烁的蓝屏那么重要)是 AnimatedOpacity 和 AnimatedCrossFade 实际上从未在此小部件中设置动画,但在其他小部件中(例如 SearchBar)

我看过例子,和我遇到的类似,但我这里不是处理图片,所以我不知道去哪里。

我也尝试过 Dart DevTools,我所能得到的只是(在时间轴中使用自下而上的视图)它卡在了“performLayout --> layout --> performLayout --> 布局"循环

有人能给我指出正确的方向吗?

以后运行遇到这个问题的人,答案如下:

Flutter 在“setState”上重建了整个有状态小部件,因此蓝色闪光是由重建整个小部件引起的——基本上是整个应用程序。要删除 flash,请将尽可能多的小部件转换为无状态小部件,以便在重建时,Flutter 不必重新重建每个小部件。