首页 > 解决方案 > 不必要的无状态小部件重建(颤振/飞镖) - 可能与 StreamBuilder 相关?

问题描述

我遇到了非常高水平的小部件重建问题。特别是当页面之间发生任何导航时。

应用背景:

我实际上是在构建一个应用程序来创建和显示集合(在这种情况下是室内植物)。身份验证、数据库和图像存储都通过 Firebase。然后,这些数据通过流传递给小部件。我所有的自定义小部件目前都是无状态的。

主页结构摘要:

我有一个显示此信息的主“图书馆”页面。此页面有一列包含“组”小部件列表。该列的主要小部件结构如下所示:

  1. 团体
    • 收藏
      • 植物瓷砖
      • 植物瓷砖
    • 收藏
      • 植物瓷砖
      • 植物瓷砖
      • 植物瓷砖
  2. 团体
    • 收藏
      • 植物瓷砖
    • 收藏
      • 植物瓷砖
      • 植物瓷砖

ETC...

显然,组、集合和 PlantTiles 的数量将根据用户提交到数据库的内容而有所不同。

问题:

每次我在应用程序的页面之间导航时,每个植物 Tile 都不会重建一次,而是 5 次。在示例图像中,有 49 个这样的图块,导致 245 次重建。PlantTiles 是无状态的,但包装在 StreamBuilder 中以显示数据。这些小部件包含图像和框阴影,这似乎对系统进行重建非常费力。

小部件重建统计信息

GridView.builder 用 StreamBuilder 包装每个 plantTile

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:plant_collector/formats/constants.dart';
import 'package:plant_collector/screens/plant.dart';
import 'package:plant_collector/widgets/dialogs/select/dialog_select.dart';
import 'package:provider/provider.dart';
import 'package:plant_collector/models/ui_builders/builders_general.dart';
import 'package:plant_collector/formats/colors.dart';

class TilePlant extends StatelessWidget {
  final Map plantMap;
  final String collectionID;
  final List<dynamic> possibleParents;
  TilePlant({
    @required this.plantMap,
    @required this.collectionID,
    @required this.possibleParents,
  });

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onLongPress: () {
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return DialogSelect(
              title: 'Move to Another Collection',
              text:
                  'Please select the collection where you would like to move this plant.',
              plantID: plantMap[kPlantID],
              listBuildColumn: Provider.of<UIBuilders>(context)
                  .createDialogCollectionButtons(
                selectedItemID: plantMap[kPlantID],
                currentParentID: collectionID,
                possibleParents: possibleParents,
              ),
            );
          },
        );
      },
      child: Container(
        decoration: BoxDecoration(
          image: plantMap[kPlantThumbnail] != null
              ? DecorationImage(
                  image: CachedNetworkImageProvider(plantMap[kPlantThumbnail]))
              : DecorationImage(
                  image: AssetImage(
                    'assets/images/default.png',
                  ),
                ),
          boxShadow: kShadowBox,
          shape: BoxShape.rectangle,
        ),
        child: FlatButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => PlantScreen(
                  plantID: plantMap[kPlantID],
                  forwardingCollectionID: collectionID,
                ),
              ),
            );
          },
          child: Column(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              plantMap[kPlantName] != null
                  ? Padding(
                      padding: EdgeInsets.all(1.0),
                      child: Container(
                        color: Color(0x44000000),
                        margin: EdgeInsets.all(2.0),
                        padding: EdgeInsets.all(3.0),
                        constraints: BoxConstraints(
                          maxHeight: 50.0,
                        ),
                        child: Text(
                          plantMap[kPlantName],
                          textAlign: TextAlign.center,
                          overflow: TextOverflow.fade,
                          style: TextStyle(
                            fontSize: 10.0,
                            color: Colors.white,
                          ),
                        ),
                      ),
                    )
                  : Container(),
            ],
          ),
        ),
      ),
    );
  }
}

我想要什么:

这些小部件没有理由更新。包装在流中的要点是,在初始创建之后,只有在传递流事件(用户修改植物数据)时才应该更新植物图块。因此,理想情况下,导航上的 plantTile 小部件重建为零(不是 5 x 49 = 245),如果植物的数据发生更改,则重建 1 次。

我已经读到 StreamBuilders 在每个屏幕构建时触发可能存在问题。我试图按照其他指南来解决这个问题,但我一定错过了一些东西,因为我似乎无法阻止它。

任何帮助将非常感激!我是新手,所以希望我没有做一些根本错误的事情。

标签: android-studioflutterdartstreamrebuild

解决方案


推荐阅读