【问题标题】:BlocBuilder doesn't get hold of the value in the new State. SEE UPDATE FlutterBlocBuilder 没有获取新状态中的值。查看更新颤振
【发布时间】:2020-06-15 02:59:13
【问题描述】:

我对 Flutter/Dart 还是很陌生,我正在使用 flutter_bloc bloc/repository 模式。 我正在努力从 bloc 方法中的存储库方法中获取值。 我的第一种方法 (I get null returned value from a method. Flutter) 是在存储库方法中收听 Stream<Position> 并返回一个 LatLng 我会在我的 bloc 方法中得到保持..我总是得到 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');
        }
      }

块:

    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. StreamTransformerhandleData 中,我向Stream&lt;LatLng&gt; locationStream 添加了来自侦听器的位置,而不是从其参数Position position 中获取位置。所以我把它改成了handleData(Position position, EventSink<LatLng> sink) => sink.add(LatLng(position.latitude, position.longitude));

  3. 在 bloc 中,我还必须收听来自 _mapRepository.getLocationStream() 的位置流。现在,因为无法直接从侦听器范围内产生状态,而从范围外产生状态只会产生当前流值并且之后不会更新,所以我不得不使用事件循环。我向该集团添加了一个 LocationUpdatedevent 从流中传递位置。

  4. 在 blocsmapEventToStateI had to react to that event yielding theLocationStream` 状态以及位置。

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

剩下要解决的唯一问题(我实际上认为我没有)是 MapScren BlocBuilder 没有获取来自新状态的值,并且在使用它时我得到 null _mapController.move(userLocation, 16);.

LatLng userLocation = (state as LocationStream).location;不是获取它的正确方法吗?

更新的代码是:

BlocBuilder:

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

存储库:

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');
    }
  }

集团:

    MapState get initialState => LocationStream(locationStream);

  @override
  Stream<MapState> mapEventToState(MapEvent event) async* {
    // user location
    if (event is GetLocationStream) {
      print('MapBloc event received : $event');
      yield* _mapGetLocationStreamToState(event);
    }
    if (event is LocationUpdated) {
      yield* _mapLocationUpdatedToState(event);
    }
  }


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

    _locationStreamSubscription =
        _mapRepository.getLocationStream().listen((LatLng location) {
          locationStream = location;
          add(LocationUpdated(locationStream));
          print(
              '_mapGetLocationStreamToState() locationStream is: $locationStream ');
        });

//    yield LocationStream(locationStream);
  }

【问题讨论】:

    标签: flutter stream


    【解决方案1】:

    找到最后一个问题。在BlocBuilderbloc: 中,如果您传递一个块,那么您实际上是在每次UI 重建时创建一个新块。

    这对于管理本地值的本地集团很有用,但在我的情况下,MapBloc 是在 main() 中创建的全局集团,所以如果我继续在 MapScreen 中创建一个新的集团,它不会得到与最后一个状态一起传入的值,导致空值。 没有通过任何集团修复它。

    class MapScreen extends StatelessWidget {
      final String name;
      final MapRepository _mapRepository;
      final MapController _mapController;
      LatLng userLocation;
      MapScreen(
          {Key key, @required this.name, @required MapRepository mapRepository})
          : assert(mapRepository != null),
            _mapRepository = mapRepository,
            _mapController = MapController(),
            super(key: key);
    
      // v1: "lift the creation of the Map Bloc to a parent widget"
      @override
      Widget build(BuildContext context) {
        return BlocBuilder<MapBloc, MapState>(
    //        bloc: MapBloc(mapRepository: _mapRepository),
            builder: (BuildContext context, MapState state) {
          userLocation = (state as LocationStream).location;
          return Scaffold(
            appBar: AppBar(
    

    希望这将有助于其他人开始,因为 Flutter 相对较新,并且没有太多关于 API 的详细解释,因此在您刚开始时很难掌握。. 例如,Geolocator API Reference 非常棒。很清楚,对每个类和参数都有详细的解释,并由一些代码示例支持..不能要求更多,实现它很容易。 flutter_bloc 不是很多(请参阅 BlocBuilder 中的 bloc 参数以了解此问题),但可以为您提供涵盖大部分需求的广泛项目,因此无论如何您都会找到理解 API 的方法。 干杯。

    【讨论】:

      猜你喜欢
      • 2021-06-01
      • 2020-06-28
      • 2021-11-19
      • 2021-05-23
      • 2020-08-04
      • 1970-01-01
      • 2021-10-21
      • 2020-07-20
      • 1970-01-01
      相关资源
      最近更新 更多