android-studio - 不必要的无状态小部件重建(颤振/飞镖) - 可能与 StreamBuilder 相关?
问题描述
我遇到了非常高水平的小部件重建问题。特别是当页面之间发生任何导航时。
应用背景:
我实际上是在构建一个应用程序来创建和显示集合(在这种情况下是室内植物)。身份验证、数据库和图像存储都通过 Firebase。然后,这些数据通过流传递给小部件。我所有的自定义小部件目前都是无状态的。
主页结构摘要:
我有一个显示此信息的主“图书馆”页面。此页面有一列包含“组”小部件列表。该列的主要小部件结构如下所示:
- 团体
- 收藏
- 植物瓷砖
- 植物瓷砖
- 收藏
- 植物瓷砖
- 植物瓷砖
- 植物瓷砖
- 收藏
- 团体
- 收藏
- 植物瓷砖
- 收藏
- 植物瓷砖
- 植物瓷砖
- 收藏
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 在每个屏幕构建时触发可能存在问题。我试图按照其他指南来解决这个问题,但我一定错过了一些东西,因为我似乎无法阻止它。
任何帮助将非常感激!我是新手,所以希望我没有做一些根本错误的事情。
解决方案
推荐阅读
- html - 实现css悬停并专注于图标的正确方法
- java - 将数据从 Map 映射到 DTO/VO 对象的有效方式
- twilio - 使用带有 JSON 的 Twilio 验证服务 API
- verilog - 为什么我不能在 Verilog 的“总是”块中将寄存器的内容复制到另一个?
- sql - 如何在SQL中比较不同表中列中的两个字符串
- php - Laravel 查询字符串到路由中的 api 调用
- bazel - 在 Bazel 中使用绝对路径是否安全?
- python - 任何人在以长复杂代码导入图像时遇到问题
- python - 如何将 8 个皇后谜题的解旋转 90 度?
- html - 如何在导航栏的内容中从左右提供空间