在 Navigator.pop 之后 StreamBuilder 不会重建

Posted

技术标签:

【中文标题】在 Navigator.pop 之后 StreamBuilder 不会重建【英文标题】:StreamBuilder doesn't rebuild after Navigator.pop 【发布时间】:2019-11-03 10:59:42 【问题描述】:

我有一个跟踪当前用户位置的简单服务:

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不再自我更新。

构建器甚至不再被调用。那么请问,这段代码有什么问题?

谢谢!

【问题讨论】:

尝试扩展StatefulWidget并在initState方法中初始化LocationService,也尝试覆盖deactivate/dispose以释放您在自定义State中初始化的资源跨度> @pskink 这就是我在使用StreamBuilder 之前所做的。可悲的是,结果是一样的。 【参考方案1】:

当您推送并弹出页面后,构建方法不会重新启动。 我在 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
        ,
    );
    ...

【讨论】:

以上是关于在 Navigator.pop 之后 StreamBuilder 不会重建的主要内容,如果未能解决你的问题,请参考以下文章

在 Navigator.pop 之后 StreamBuilder 不会重建

来自 FutureBuilder 的 Navigator.pop

Flutter 图像在 navigator pop 上再次下载

Navigator.pop() - 如何传递 `context` 以供导航器读取 -

运行 navigator.pop() 后如何刷新 React 状态?

Navigator.pop(context) 不返回上一屏 Flutter