BlocBuilder не получает значения в новом состоянии. СМОТРЕТЬ ОБНОВЛЕНИЕ Флаттер - PullRequest
0 голосов
/ 02 марта 2020

Я все еще очень плохо знаком с Flutter / Dart и использую шаблон flutter_blo c bloc / repository. Я изо всех сил пытаюсь получить значение из метода репозитория обратно в методе blo c. Мой первый подход ( Я получаю нулевое возвращаемое значение из метода. Flutter ) состоял в том, чтобы прослушать Stream<Position> в методе репозитория и вернуть LatLng, который я получил бы в своем блоке c method..I всегда получает значение null.

Так что мой новый подход заключается в использовании StreamTransformer для преобразования этого Stream<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');
        }
      }

blo c:

    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 handleData я добавил к Stream<LatLng> locationStream местоположение слушателя вместо того, чтобы взять его из аргумента Position position. Поэтому я изменил его на handleData(Position position, EventSink<LatLng> sink) => sink.add(LatLng(position.latitude, position.longitude));.

  3. В блоке c Мне также пришлось прослушивать поток местоположения с _mapRepository.getLocationStream(). Теперь, поскольку вывод состояния непосредственно из области прослушивателя невозможен, а вывод его из-за пределов областей просто возвращает текущее значение потока и не обновляется после этого, мне пришлось использовать цикл событий. Я добавил к событию blo c a LocationUpdated, проходящему в месте из потока.

  4. в blo cs mapEventToState I had to react to that event yielding the LocationStream` вместе с местоположение.

Теперь состояния текут, как и ожидалось, с новым значением местоположения вместе с ними.

Единственная проблема, которую осталось решить (которую я на самом деле думал, что не сделал есть) это то, что MapScren BlocBuilder не получает значение, поступающее из нового состояния, и я получаю нулевое значение при его использовании, как в _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');
    }
  }

blo c:

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

1 Ответ

0 голосов
/ 03 марта 2020

Нашел последнюю проблему. В BlocBuilder bloc: если вы передаете блок blo c, вы фактически создаете новый блок blo c каждый раз, когда пользовательский интерфейс перестраивает.

Это полезно для локального блока c, который управляет локальными значениями, но в моем случае MapBloc - это глобальный блок c, созданный в main(), поэтому, если я продолжу создавать новое значение в MapScreen, он не получит значение, переданное с последним состоянием, в результате в нулевом значении. Не пропуская ни одного blo c исправленного.

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, которые затрудняют gr asp когда вы только начинаете .. Например, Geolocator API Reference - fantasti c. Это понятно, есть подробное объяснение каждого класса и параметра, и подкреплено каким-то примером кода ... не могу просить больше, и это было легко реализовать. flutter_blo c не так много (см. параметр blo c в BlocBuilder для этого вопроса), но предоставляет вам широкий спектр проектов, охватывающих большинство ваших потребностей, так что вы все равно найдете свой способ понять API. Приветствия.

...