等待未来流发出的 StreamBuilder

StreamBuilder that waits for a stream on a future to emit

return ref.watch(findStoreProvider).when(
            data: (store) {
              _store = store;
              return _map;
            },
            error: (error, stackTrace) => Text(error.toString()),
            loading: () => VpLoadingPage(text: 'Loading Google map'));
      }

我需要上面的代码保持加载状态,直到 store.map$ 发出一次(发生在提供程序 class 底部的 findVgnItms() 中)。因此,它本质上是一个 StreamBuilder,等待未来的流发出。这是怎么做到的?我期待这个:ref.watch(findStoreProvider) 被转换为流并与 store.$map 结合,但那是在未来所以似乎不可能?:

    return ref.watch(findStoreProvider).when(
        data: (store) {
          _store = store;
          return _map;
        },
        error: (error, stackTrace) => Text(error.toString()),
        loading: () => VpLoadingPage(text: 'Loading Google map'));
  }
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    if (defaultTargetPlatform == TargetPlatform.android) {
      AndroidGoogleMapsFlutter.useAndroidViewSurface = true;
    }
    _vm = ref.watch(findPageVm);
    _widgetRef = ref;

    return ref.watch(findStoreProvider).when(
        data: (store) {
          _store = store;
          return _map;
        },
        error: (error, stackTrace) => Text(error.toString()),
        loading: () => VpLoadingPage(text: 'Loading Google map'));
  }

  Widget get _map {
    return StreamBuilder(
        stream: _store.map$,
        builder: (context, AsyncSnapshot<VpMap> snapshot) {
          return _googleMap(map: snapshot.data);
        });
  }

  Widget _googleMap({VpMap? map}) {
    final x = _widgetRef.watch(provider1);
    return Stack(children: [
      VpLoadingPage(text: 'Loading Google map'),
      AnimatedOpacity(
          curve: Curves.fastOutSlowIn,
          opacity: x ? 1.0 : 0,
          duration: const Duration(milliseconds: 600),
          child: GoogleMap(
            markers: map?.markers ?? const <Marker>{},
            myLocationEnabled: true,
            initialCameraPosition: CameraPosition(
              target: LatLng(
                  _store.userPosition.latitude, _store.userPosition.longitude),
              zoom: map?.zoom ?? 13,
            ),
            onMapCreated: (GoogleMapController controller) {
              _vm.controller.complete(controller);

              Future.delayed(const Duration(milliseconds: 550),
                  () => _widgetRef.read(provider1.notifier).isLoaded());
            },
          )),
    ]);
  }

class 有未来提供者的流:

final findStoreProvider = FutureProvider((provider) async {
  final userStore = await provider.watch(userStoreProvider.future);
  return FindStore(provider, userStore: userStore);
});

class FindStore extends Store {
  FindStore(this.$provider, {required UserStore userStore}) {
    map$ ??= _mapController.stream;
    findVgnItms();
    _userStore = userStore;
  }

  final Ref $provider;
  Stream<VpMap>? map$;
  late final StreamController<VpMap> _mapController =
      StreamController.broadcast();
  late UserStore _userStore;
  Set<Marker> markers = <Marker>{};
  Stream<String?>? searchTerm;

  Position get userPosition => _userStore.userPosition;

  Future<List<VgnItmEst>> _$search(String searchTerm) async {
    final result =
        await $provider.watch(searchResultsProvider(searchTerm).future);
    return result;
  }

  Set<Marker> _mapSearchResultsToMarkers(List<VgnItmEst> searchResults) {
    return searchResults
        .map((searchResult) => Marker(
            markerId: MarkerId(searchResult.id.toString()),
            position: LatLng(searchResult.establishment!.location!.lat,
                searchResult.establishment!.location!.lng)))
        .toSet();
  }

  Future<FindStore> findVgnItms([String searchTerm = '']) async {
    markers = _mapSearchResultsToMarkers(await _$search(searchTerm));
    final map = VpMap(position: _userStore.userPosition, markers: markers);
    _mapController.add(map);
    return this;
  }
}

如果你需要一个应该等待 Future 完成的 Stream,你可能需要查看 async generatorsasync*yield* 个关键字。

这是一个简短的例子:

Stream<MyObject> getStreamThatWaitsOnFuture() async* {
  await functionThatReturnsAFuture();
  yield* functionThatReturnsAStream();
}

我在这里写了一个简短的post:https://medium.com/@dumazy/create-a-stream-that-requires-a-future-in-dart-692f6f089a7e