等待未来流发出的 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 generators 和 async*
和 yield*
个关键字。
这是一个简短的例子:
Stream<MyObject> getStreamThatWaitsOnFuture() async* {
await functionThatReturnsAFuture();
yield* functionThatReturnsAStream();
}
我在这里写了一个简短的post:https://medium.com/@dumazy/create-a-stream-that-requires-a-future-in-dart-692f6f089a7e
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 generators 和 async*
和 yield*
个关键字。
这是一个简短的例子:
Stream<MyObject> getStreamThatWaitsOnFuture() async* {
await functionThatReturnsAFuture();
yield* functionThatReturnsAStream();
}
我在这里写了一个简短的post:https://medium.com/@dumazy/create-a-stream-that-requires-a-future-in-dart-692f6f089a7e