Introduction
I’m working with riverpod for state management in my application.
I simply want to update a variable when I call my notifier.
The problem occurs when I inject my service into this notifier.
Code
Here is my simplified page, I have a button which updates the orientation of my map through a mapOrientationNotifier
.
I also display the compass orientation in real time through a mapCompassNotifier
.
map_page.dart:
class MapPage extends ConsumerWidget {
const MapPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final mapCompassNotifier = ref.watch(mapCompassNotifierProvider);
final mapOrientationNotifier = ref.watch(mapOrientationNotifierProvider);
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
title: mapCompassNotifier.compass != null
? Text('Direction: ${mapCompassNotifier.compass!.degree!.toStringAsFixed(2)}°')
: const Text('Direction: 0°'),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: (){
print("Button pressed. Current mapOrientationState: ${mapOrientationNotifier.mapOrientationState}"); // Debug print
mapOrientationNotifier.updateMapOrientationState();
},
child: mapOrientationNotifier.mapOrientationState == MapOrientationState.north
? const Icon(Icons.navigation)
: const Icon(Icons.assistant_navigation),
),
],
),
body: FlutterMap(
... some code
),
);
}
}
Well now let’s update the mapOrientationState
variable through the updateMapOrientationState
method in my mapOrientationNotifier
.
map_orientation_notifier.dart:
final mapOrientationNotifierProvider = ChangeNotifierProvider((ref) {
return MapOrientationNotifierProvider(
mapController: ref.watch(mapControllerProvider),
);
});
class MapOrientationNotifierProvider extends ChangeNotifier {
final MapController mapController;
MapOrientationState mapOrientationState = MapOrientationState.north;
bool _isDisposed = false;
MapOrientationNotifierProvider({
required this.mapController,
});
void updateMapOrientationState() {
if (_isDisposed) return;
if (mapOrientationState == MapOrientationState.north) {
mapOrientationState = MapOrientationState.heading;
} else if (mapOrientationState == MapOrientationState.heading) {
mapOrientationState = MapOrientationState.north;
mapController.rotate(0);
}
notifyListeners();
}
@override
void dispose() {
_isDisposed = true;
super.dispose();
}
}
It works no problem.
Now I would like to inject a compass Service
which I use to retrieve the orientation of the compass in real time.
My compassService
works since I can display the value in the appBar in map_page.dart
through the compassNotifier
.
compass_service.dart:
final compassServiceProvider = ChangeNotifierProvider<CompassService>((ref) {
return CompassService(
getCompassUseCase: ref.watch(getCompassUseCaseProvider),
);
});
class CompassService with ChangeNotifier {
final GetCompassUseCase getCompassUseCase;
CompassService({
required this.getCompassUseCase,
}){
_subscribeToCompass();
}
StreamSubscription<ResultEntity<CompassEntity?, AppException>>? _compassSubscription;
CompassEntity? _compass;
CompassEntity? get compass => _compass;
void _subscribeToCompass() {
_compassSubscription = getCompassUseCase.execute().listen(
(result) {
result.toResult(
success: (compass) {
_compass = compass;
notifyListeners();
},
failure: (_) {
_compass = null;
notifyListeners();
},
);
},
onError: (error) {
_compass = null;
notifyListeners();
}
);
}
@override
void dispose() {
_compassSubscription?.cancel();
super.dispose();
}
}
map_compass_notifier.dart:
final mapCompassNotifierProvider = ChangeNotifierProvider((ref) {
return MapCompassNotifierProvider(
compassService: ref.watch(compassServiceProvider),
);
});
class MapCompassNotifierProvider extends ChangeNotifier{
final CompassService compassService;
MapCompassNotifierProvider({
required this.compassService,
}){
_initialize();
}
CompassEntity? get compass => compassService.compass;
LocationMarkerHeading? get userHeading => compassService.compass != null
? UserMarkerHelper.convertToLocationMarkerHeading(compass: compassService.compass!)
: null;
void _initialize() {
compassService.addListener(_updateCompass);
}
void _updateCompass() {
notifyListeners();
}
@override
void dispose() {
compassService.removeListener(_updateCompass);
super.dispose();
}
}
Code with service not works
Now that all this is in place I want to be able to inject my compass service into the mapOrientationNotifier
so that I can use the compass value to rotate my map when I change the orientation with mapOrientationState
.
Let’s take my mapOrientationNotifier
and inject the service:
map_orientation_notifier.dart:
final mapOrientationNotifierProvider = ChangeNotifierProvider((ref) {
return MapOrientationNotifierProvider(
mapController: ref.watch(mapControllerProvider),
compassService: ref.watch(compassServiceProvider), // => Add this line
);
});
class MapOrientationNotifierProvider extends ChangeNotifier {
final MapController mapController;
final CompassService compassService; // => Add this line
MapOrientationState mapOrientationState = MapOrientationState.north;
bool _isDisposed = false;
MapOrientationNotifierProvider({
required this.mapController,
required this.compassService, // => Add this line
}) {
compassService.addListener(_onCompassChanged); // => Add this line
}
// => Add this method
void _onCompassChanged() {
if (_isDisposed) return;
if (mapOrientationState == MapOrientationState.heading) {
if (compassService.compass?.degree != null) {
//mapController.rotate(compassService.compass!.degree!);
}
}
notifyListeners();
}
void updateMapOrientationState() {
if (_isDisposed) return;
if (mapOrientationState == MapOrientationState.north) {
mapOrientationState = MapOrientationState.heading;
} else if (mapOrientationState == MapOrientationState.heading) {
mapOrientationState = MapOrientationState.north;
//mapController.rotate(0);
}
notifyListeners();
}
@override
void dispose() {
_isDisposed = true;
compassService.removeListener(_onCompassChanged); // => Add this line
super.dispose();
}
}
Problem
So I just injected the service but the mapOrientationState variable is no longer updated, I don’t understand…