StreamBuilder 在 Navigator.pop 后不重建
StreamBuilder doesn't rebuild after Navigator.pop
我有一个跟踪当前用户位置的简单服务:
class LocationService {
LatLng _lastLocation;
Location location = Location();
StreamController<LatLng> _locationController = StreamController<LatLng>();
Stream<LatLng> get locationStream => _locationController.stream;
LocationService() {
location.onLocationChanged().listen((locationData) {
LatLng location = LatLng(locationData.latitude, locationData.longitude);
if(_lastLocation == null || _lastLocation != location) {
_lastLocation = location;
_locationController.add(location);
}
});
}
}
然后,我正在使用此服务创建一个地图(感谢 flutter_map),它遵循当前用户位置:
class SelfUpdatingMap extends StatelessWidget {
final Icon currentPositionIcon;
final MapController _controller = MapController();
SelfUpdatingMap({
this.currentPositionIcon,
});
@override
Widget build(BuildContext context) => StreamBuilder<LatLng>(
stream: LocationService().locationStream,
builder: (context, asyncSnapshot) {
if (asyncSnapshot.hasError || asyncSnapshot.data == null) {
return Text('Loading...');
}
try {
_controller?.move(asyncSnapshot.data, 18);
} catch (ignored) {}
return _createMapWidget(context, asyncSnapshot.data);
},
);
Widget _createMapWidget(BuildContext context, LatLng location) => FlutterMap(
options: MapOptions(
center: location,
zoom: 18,
),
layers: [
TileLayerOptions(
urlTemplate: 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png', // https://a.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png is good too.
subdomains: ['a', 'b', 'c'],
),
MarkerLayerOptions(
markers: [
Marker(
width: 40,
height: 40,
point: location,
builder: (contact) => currentPositionIcon,
),
]
),
],
mapController: _controller,
);
}
然后,我在两个地方使用 SelfUpdating
小部件:
- 第 1 页,第 2 页 的祖先。
- 并且在 第 3 页 中,第 2 页 的继承者。
情况是这样的:
- 我启动我的应用程序,我在 第 1 页。我有我的
SelfUpdatingMap
.
- 我叫
Navigator.pushNamed(context, '/page-2')
.
- 我打电话给
Navigator.pushNamed(context, '/page-3')
。我还有一个 SelfUpdatingMap
.
- 我调用了两次
Navigator.pop(context)
,我得到了 第 1 页 但是 SelfUpdatingMap
没有自己更新了。
生成器甚至不再被调用。那么,请问这段代码有什么问题?
谢谢!
当您推送并弹出页面后,构建方法不会重新启动。
我发现 FlutterBluetoothSerial.instance.onStateChanged() 流有同样的问题,我找到的解决方案是将流添加到本地静态最终变量并使用它而不是每次调用原始方法时调用它(只有当我认为流是广播。
解决方案示例:
class ExampleClass {
static final Stream<LatLng> locationStream = LocationService().locationStream;
}
class SelfUpdatingMap extends StatelessWidget {
...
@override
Widget build(BuildContext context) => StreamBuilder<LatLng>(
stream: ExampleClass.locationStream,
builder: (context, asyncSnapshot) {
if (asyncSnapshot.hasError || asyncSnapshot.data == null) {
return Text('Loading...');
}
try {
_controller?.move(asyncSnapshot.data, 18);
} catch (ignored) {}
return _createMapWidget(context, asyncSnapshot.data);
},
);
...
}
class Page3Widget extends StatelessWidget {
...
@override
Widget build(BuildContext context) => StreamBuilder<LatLng>(
stream: ExampleClass.locationStream,
builder: (context, asyncSnapshot) {
//do something
},
);
...
}
我有一个跟踪当前用户位置的简单服务:
class LocationService {
LatLng _lastLocation;
Location location = Location();
StreamController<LatLng> _locationController = StreamController<LatLng>();
Stream<LatLng> get locationStream => _locationController.stream;
LocationService() {
location.onLocationChanged().listen((locationData) {
LatLng location = LatLng(locationData.latitude, locationData.longitude);
if(_lastLocation == null || _lastLocation != location) {
_lastLocation = location;
_locationController.add(location);
}
});
}
}
然后,我正在使用此服务创建一个地图(感谢 flutter_map),它遵循当前用户位置:
class SelfUpdatingMap extends StatelessWidget {
final Icon currentPositionIcon;
final MapController _controller = MapController();
SelfUpdatingMap({
this.currentPositionIcon,
});
@override
Widget build(BuildContext context) => StreamBuilder<LatLng>(
stream: LocationService().locationStream,
builder: (context, asyncSnapshot) {
if (asyncSnapshot.hasError || asyncSnapshot.data == null) {
return Text('Loading...');
}
try {
_controller?.move(asyncSnapshot.data, 18);
} catch (ignored) {}
return _createMapWidget(context, asyncSnapshot.data);
},
);
Widget _createMapWidget(BuildContext context, LatLng location) => FlutterMap(
options: MapOptions(
center: location,
zoom: 18,
),
layers: [
TileLayerOptions(
urlTemplate: 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}.png', // https://a.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png is good too.
subdomains: ['a', 'b', 'c'],
),
MarkerLayerOptions(
markers: [
Marker(
width: 40,
height: 40,
point: location,
builder: (contact) => currentPositionIcon,
),
]
),
],
mapController: _controller,
);
}
然后,我在两个地方使用 SelfUpdating
小部件:
- 第 1 页,第 2 页 的祖先。
- 并且在 第 3 页 中,第 2 页 的继承者。
情况是这样的:
- 我启动我的应用程序,我在 第 1 页。我有我的
SelfUpdatingMap
. - 我叫
Navigator.pushNamed(context, '/page-2')
. - 我打电话给
Navigator.pushNamed(context, '/page-3')
。我还有一个SelfUpdatingMap
. - 我调用了两次
Navigator.pop(context)
,我得到了 第 1 页 但是SelfUpdatingMap
没有自己更新了。
生成器甚至不再被调用。那么,请问这段代码有什么问题?
谢谢!
当您推送并弹出页面后,构建方法不会重新启动。 我发现 FlutterBluetoothSerial.instance.onStateChanged() 流有同样的问题,我找到的解决方案是将流添加到本地静态最终变量并使用它而不是每次调用原始方法时调用它(只有当我认为流是广播。
解决方案示例:
class ExampleClass {
static final Stream<LatLng> locationStream = LocationService().locationStream;
}
class SelfUpdatingMap extends StatelessWidget {
...
@override
Widget build(BuildContext context) => StreamBuilder<LatLng>(
stream: ExampleClass.locationStream,
builder: (context, asyncSnapshot) {
if (asyncSnapshot.hasError || asyncSnapshot.data == null) {
return Text('Loading...');
}
try {
_controller?.move(asyncSnapshot.data, 18);
} catch (ignored) {}
return _createMapWidget(context, asyncSnapshot.data);
},
);
...
}
class Page3Widget extends StatelessWidget {
...
@override
Widget build(BuildContext context) => StreamBuilder<LatLng>(
stream: ExampleClass.locationStream,
builder: (context, asyncSnapshot) {
//do something
},
);
...
}