BlocBuilder 无法掌握新状态中的值。请参阅更新颤振



我对Flutter/Dat还是个新手,我使用的是Flutter_bloc block/repository模式。我正在努力从存储库方法中获取值,并将其返回到bloc方法中。我的第一种方法(我从一个方法.Flutter获得null返回值(是在存储库方法中侦听一个Stream<Position>,并返回一个我将在bloc方法中获得的LatLng。。我总是空着。

因此,我的新方法是使用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<LatLng> locationStream添加了一个来自侦听器的位置,而不是从其参数Position position中获取。所以我把它改成了handleData(Position position, EventSink<LatLng> sink) => sink.add(LatLng(position.latitude, position.longitude));

  3. 在block中,我还必须收听来自_mapRepository.getLocationStream()的位置流。现在,因为直接从侦听器范围内产生状态是不可能的,而从范围外产生状态只会产生当前流值,之后不会更新,所以我不得不使用事件循环。我在区块中添加了一个从流中经过该位置的LocationUpdated事件。

  4. 在块CCD_ 16映射EventToState CCD_。

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

剩下的唯一需要解决的问题(我实际上认为我没有(是MapScrenBlocBuilder无法获得来自新状态的值,并且当我像在_mapController.move(userLocation, 16);中那样使用它时,会得到null。

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

找到最后一个问题。在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参考非常棒。很清楚,对每个类和参数都有详细的解释,并有一些代码示例支持。。不能要求更多,而且实施它很容易。flatter_bloc没有那么多(关于这个问题,请参阅BlocBuilder中的bloc参数(,但它为您提供了一系列广泛的项目,涵盖了您的大多数需求,因此您无论如何都会找到理解API的方法。干杯

相关内容

最新更新