BlocBuilder不会在新状态中保留值。查看更新Flutter

时间:2020-03-02 19:12:39

标签: flutter stream

我对Flutter / Dart还是很陌生,并且正在使用flutter_bloc块/存储库模式。 我正在努力从bloc方法中的存储库方法中获取值。 我的第一种方法(I get null returned value from a method. Flutter)是在存储库方法中侦听Stream<Position>,然后返回将在我的bloc方法中保留的LatLng。我总是得到null。

因此,我的新方法是使用StreamTransformerStream<Position>转换为Stream<LatLng>,但由于出现.transform的问题,我一直在编写存储库方法无法使用,我得到了错误 The method 'transform' isn't defined for the class 'Function'。 你能看到我做错了吗? 一如既往的感谢。

我的两种方法是:

存储库:

    StreamSubscription _positionStreamSubsciption;

    Stream<LatLng> getLocationStream() {
        print('getLocationStream() called');
        print('isTracking was : $isTracking');
        LatLng location;
        Stream<LatLng> locationStream;
        LocationOptions locationOptions = LocationOptions(
            accuracy: LocationAccuracy.bestForNavigation, distanceFilter: 0);
        try {
          if (isTracking == true) {
            _positionStreamSubsciption.cancel();
          } else {
            _positionStreamSubsciption = locationManager
                .getPositionStream(locationOptions)
                .listen((Position position) {
              if (position != null) {
                location = LatLng(position.latitude, position.longitude);

                handleData(Position position, EventSink<LatLng> sink) =>
                    sink.add(location);

                final transformer =
                    StreamTransformer<Position, LatLng>.fromHandlers(
                        handleData: handleData);
                return _positionStreamSubsciption.onData.transform(transformer); // .transform trows an ERROR
              }
              print('getLocationStream() location is : $location');
            });
          }

          isTracking = !isTracking;
          print('isTracking is : $isTracking');
        } catch (error) {
          print('startTracking error: $error');
        }
      }

bloc:

    LatLng locationStream;
    StreamSubscription _locationStreamSubscription;


    Stream<MapState> _mapGetLocationStreamToState(
          GetLocationStream event) async* {
        print('_mapGetLocationStreamToState event received : $event');

        _locationStreamSubscription =
            _mapRepository.getLocationStream().listen((LatLng location) {
          locationStream = location;
        });

更新:

经过一段时间的代码摆弄之后,我发现了错误所在:

  1. 在存储库中,我确实设置了一个侦听器,但实际上需要流本身,因此我添加了_positionStream = locationManager.getPositionStream(locationOptions);

  2. StreamTransformer的{​​{1}}中,我在监听器的位置添加了handleData,而不是从其参数Stream<LatLng> locationStream中获取它。所以我将其更改为Position position

  3. 在bloc中,我还必须收听handleData(Position position, EventSink<LatLng> sink) => sink.add(LatLng(position.latitude, position.longitude));中的位置流。现在,由于不可能直接从侦听器作用域内部产生状态,而从作用域外部产生状态只会产生当前流值,并且此后不会更新,因此我不得不使用事件循环。我向集团添加了一个_mapRepository.getLocationStream()事件,该事件从流中传递到该位置。

  4. 位于LocationUpdated mapEventToState s LocationStream状态中,以及位置。

现在状态如预期般流动,并带有新的位置值。

要解决的唯一问题(我实际上以为我没有)是I had to react to that event yielding the MapScren不能容纳来自新状态的值,而当像BlocBuilder中一样使用它。

_mapController.move(userLocation, 16);不是正确的方法吗?

更新的代码是:

BlocBuilder:

LatLng userLocation = (state as LocationStream).location;

存储库:

bloc: MapBloc(mapRepository: _mapRepository),
        builder: (BuildContext context, MapState state) {
          LatLng userLocation = (state as LocationStream).location;
          return Scaffold(
..

bloc:

Stream<LatLng> getLocationStream() {
    print('getLocationStream() called');
    print('isTracking was : $isTracking');
    Stream<LatLng> locationStream;
    Stream<Position> _positionStream;
    LocationOptions locationOptions = LocationOptions(
        accuracy: LocationAccuracy.bestForNavigation, distanceFilter: 0);
    try {
      if (isTracking == true) {
        _positionStreamSubsciption.cancel();
      } else {
        _positionStream = locationManager.getPositionStream(locationOptions);

        handleData(Position position, EventSink<LatLng> sink) =>
            sink.add(LatLng(position.latitude, position.longitude));

        final transformer = StreamTransformer<Position, LatLng>.fromHandlers(
            handleData: handleData);
        locationStream = _positionStream.transform(transformer);
        return locationStream;
      }

      isTracking = !isTracking;
      print('isTracking is : $isTracking');
    } catch (error) {
      print('startTracking error: $error');
    }
  }

1 个答案:

答案 0 :(得分:0)

找到了最后一个问题。在BlocBuilder的{​​{1}}中,如果您通过一个Bloc,则实际上是在每次UI重建时都在创建一个新的Bloc。

这对于管理本地值的本地集团很有用,但是在我的情况下,bloc:是在MapBloc中创建的全局集团,因此如果我继续在main()中创建一个新集团它没有获得通过上一状态传递的值,从而导致空值。 不通过任何集团来解决它。

MapScreen

希望这将对其他人有所帮助,因为Flutter相对较新,并且关于API的详细解释并不多,因此刚开始时很难掌握。 例如,《 Geolocator API参考》非常棒。很明显,对每个类和参数都有详细的解释,并有一些代码示例作为后盾..不需要更多,实现它很容易。 flutter_bloc并不是很多(有关此问题,请参见BlocBuilder中的bloc参数),但是可以为您提供满足大部分需求的大量项目,因此无论如何您都会找到理解API的方法。 干杯。