我有一个使用相机插件的Flutter项目。在此插件中,我计算每个帧上的每个FPS,然后使用EventChannel将结果发送回Flutter。在Flutter端,我正在使用StreamProvider来仅更新显示实时FPS的TextWidget。
在我的小部件树顶部:
StreamProvider<FPSData>.value(value: initiated==false? null : streamControllerFPS.stream)
我正在通过以下方式将fps值添加到streamController中
FPSData fpsData = new FPSData(event['fps'])
streamControllerFPS.add(fpsData);
class FPSData{
int value;
FPSData(dynamic data){
value = data.round();
}
}
在我的TextWidget(小部件树的底部)中:
class FPSWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
debugPrint("Building FPSWidget");
FPSData fpsData;
fpsData = Provider.of<FPSData>(context);
if(fpsData==null)
return Container();
return Text("fps: "+fpsData.value.toString());
}
}
所有这些工作都按预期进行:每次将新的FPS值添加到流中时,FPS文本小部件都会重新绘制。
现在,我想知道的是,当FPS值更改时,是否有可能仅重绘窗口小部件。示例:如果上一个FPS值为31,新值也为31,我想跳过重建文本小部件的操作。 我知道使用ChangeNotifier很明显,但是我希望可以使用StreamProvider进行相同的操作。
到目前为止,我已经尝试了两种不同的解决方案:
StreamProvider<FPSData>.value(value: initiated==false? null : streamControllerFPS.stream.where((newFPS) => newFPS.value!=lastFPSValue))
我使用.listen()方法保存 lastFPSValue 。似乎只有在FPS更改时才调用Provider.of,但是即使将StreamController和Stream设置为广播,我的TextWidget中也只能得到一个空值。
updateShouldNotify: (_, __) => true
,但这也没有解决。似乎该问题可能是由于先前的FPSData(31)始终与新的FPSData(31)不同而引起的。我不知道如何使它们相等。如果有人可以帮助我,我将不胜感激!预先感谢
答案 0 :(得分:0)
在FPSData类中添加bool运算符似乎可以解决问题!我不会将其视为已被接受的答案,因为这样做可能会有更有效/正确的方式。
@immutable
class FPSData{
final value;
FPSData(this.value){
}
bool operator ==(Object fpsDataCompare) {
return ((fpsDataCompare as FPSData).value == value);
}
}
答案 1 :(得分:0)
Provider有一个名为Selector的整洁小部件,它使用提供的值并仅在满足条件时(例如,值不同时)才更新构建器
final value = context.select<FPSData, int>((FPSData fps) => fps.value); //this will update the fps value and rebuild only if the previous and new value are different
if(value == null) return Container();
return Text("fps: $value ");
这与Provider程序包的Selector小部件相同
return Selector<FPSData, int>(
selector: (_, fps) => fps.value,
shouldRebuild: (prev, curr) => prev != curr, //this compare the previous and current value, if you don't set this it will just use the default
//DeepCollectionEquality().equals(value, selected) which does the same, but works too if the parameters are iterables (List, Map, etc)
builder: (_, value, __) {
if(value == null) return Container();
return Text("fps: $value");
},
);
第一个代码实际上是Provider 4.1.0中添加的一个新实现,但不太冗长,而且第一个代码不允许您更改shouldREbuild方法,以防您想应用更多的逻辑,而不仅仅是检查它们是否不同
也要添加
添加updateShouldNotify:(_,__)=>是,但这还行不通 出来。看来问题可能是由于事实 以前的FPSData(31)总是不同于新的 FPSData(31)。我不知道如何使它们相等。
那是因为您总是返回true,而不检查它们是否确实不同,也许可以这样尝试
updateShouldNotify: (prev, curr) => prev?.value != curr?.value
现在它将检查值是否不同并通知它们是否