[Help Wanted]: Odometer value does not update when the app is terminated.
Required Reading
- [x] Confirmed
Plugin Version
flutter_background_geolocation: ^4.16.9
Mobile operating-system(s)
- [ ] iOS
- [x] Android
Device Manufacturer(s) and Model(s)
Samsung Galaxy A12
Device operating-systems(s)
Android 13
What do you require assistance about?
I'm currently sending the final odometer value to the server when a task is completed. However, I'm facing an issue where the odometer value resets to zero if the app is terminated and restarted. This leads to inaccurate distance tracking for the user. Could you help me identify what I might be missing or suggest how to persist the odometer value across app restarts?
[Optional] Plugin Code and/or Config
// Add this function outside main()
final log = logger.Logger();
// Headless task for background location updates
@pragma('vm:entry-point')
void backgroundGeolocationHeadlessTask(bg.HeadlessEvent event) async {
try {
log.i('[HeadlessTask] Event: ${event.name}');
switch (event.name) {
case bg.Event.LOCATION:
final location = event.event;
break;
case bg.Event.HEARTBEAT:
await bg.BackgroundGeolocation.sync();
break;
case bg.Event.TERMINATE:
break;
}
} catch (e, st) {
log.e('Headless task error', error: e, stackTrace: st);
}
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
GestureBinding.instance.resamplingEnabled = true;
bg.BackgroundGeolocation.ready(bg.Config(
reset: true,
debug: true,
preventSuspend: true,
logLevel: bg.Config.LOG_LEVEL_VERBOSE,
desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH,
distanceFilter: 10.0,
heartbeatInterval: 60,
disableElasticity: true,
isMoving: true,
locationUpdateInterval: 15000,
fastestLocationUpdateInterval: 10000,
deferTime: 0,
forceReloadOnBoot: true,
forceReloadOnGeofence: true,
forceReloadOnHeartbeat: true,
pausesLocationUpdatesAutomatically: false,
showsBackgroundLocationIndicator: true,
useSignificantChangesOnly: false,
activityRecognitionInterval: 1000,
backgroundPermissionRationale: bg.PermissionRationale(
title: "Allow ${dotenv.get('APP_NAME')} to access this device's location even when the app is closed or not in use.",
message: "This app collects location data to enable recording your trips to work and calculate distance-travelled.",
positiveAction: 'Change to "{backgroundPermissionOptionLabel}"',
negativeAction: 'Cancel'),
stopOnTerminate: false,
locationAuthorizationRequest: 'Always',
persistMode: 1,
autoSync: true,
startOnBoot: true,
enableHeadless: true))
.then((bg.State state) async {
print("[ready] ${state.toMap()}");
if (state.schedule!.isNotEmpty) {
bg.BackgroundGeolocation.startSchedule();
}
if (state.enabled) {}
}).catchError((error) {
print('[ready] ERROR: $error');
});
// Register headless task
bg.BackgroundGeolocation.registerHeadlessTask(backgroundGeolocationHeadlessTask);
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) {
runApp(const App());
});
}
startTaskTracking(String taskId) async {
bg.State state = await bg.BackgroundGeolocation.state;
if (!state.enabled) {
await bg.TransistorAuthorizationToken.destroy(dotenv.get('LOCATION_BASE_URL'));
await bg.BackgroundGeolocation.setConfig(bg.Config(
transistorAuthorizationToken: await bg.TransistorAuthorizationToken.findOrCreate("Beta24", taskId, dotenv.get('LOCATION_BASE_URL')),
desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH,
foregroundService: true,
notification: bg.Notification(
title: "Task Location Tracking",
text: "Tracking your location for accurate distance calculation",
channelName: "Task Tracking",
sticky: true,
priority: bg.Config.NOTIFICATION_PRIORITY_MAX)));
bg.BackgroundGeolocation.setOdometer(0.0);
await bg.BackgroundGeolocation.strat();
CommonFunctions.showSuccessToast("Location Tracking Started");
// Force a location update immediately
await bg.BackgroundGeolocation.getCurrentPosition(persist: true, desiredAccuracy: 0, timeout: 30000, samples: 3)
.then((bg.Location location) {
debugPrint("[getCurrentPosition] ${location.toMap()}");
}).catchError((error) {
debugPrint("[getCurrentPosition] ERROR: $error");
});
}
}
Future<void> stopTaskTracking() async {
await bg.BackgroundGeolocation.stop();
await bg.TransistorAuthorizationToken.destroy(dotenv.get('LOCATION_BASE_URL'));
bg.BackgroundGeolocation.destroyLocations();
bg.BackgroundGeolocation.removeListeners();
bg.BackgroundGeolocation.setOdometer(0.0);
}
[Optional] Relevant log output
If I were you, I’d disable everywhere that . setOdometer(0.0) is called, to determine if that is the source of my problem.
On an unrelated note, where did you get the idea to use these options?
forceReloadOnBoot: true, forceReloadOnGeofence: true, forceReloadOnHeartbeat: true,
If I remove the specified methods, is it possible that background location updates will start working correctly? I'm trying to determine whether those implementations are interfering with background tracking.
Updated -----
@pragma('vm:entry-point') void backgroundGeolocationHeadlessTask(bg.HeadlessEvent event) async { try { log.i('[HeadlessTask] Event: ${event.name}');
switch (event.name) {
case bg.Event.LOCATION:
final location = event.event;
HydratedBloc.storage.write("odometer", location.odometer);
log.f("LOCATION UPDATE ---> $location");
break;
case bg.Event.HEARTBEAT:
await bg.BackgroundGeolocation.sync();
break;
case bg.Event.TERMINATE:
break;
}
} catch (e, st) { log.e('Headless task error', error: e, stackTrace: st); } }
bg.BackgroundGeolocation.ready(bg.Config( reset: true, debug: true, preventSuspend: true, logLevel: bg.Config.LOG_LEVEL_VERBOSE, desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH, distanceFilter: 10.0, heartbeatInterval: 60, disableElasticity: true, isMoving: true, locationUpdateInterval: 15000, fastestLocationUpdateInterval: 10000, deferTime: 0, pausesLocationUpdatesAutomatically: false, showsBackgroundLocationIndicator: true, backgroundPermissionRationale: bg.PermissionRationale( title: "Allow ${dotenv.get('APP_NAME')} to access this device's location even when the app is closed or not in use.", message: "This app collects location data to enable recording your trips to work and calculate distance-travelled.", positiveAction: 'Change to "{backgroundPermissionOptionLabel}"', negativeAction: 'Cancel'), stopOnTerminate: false, locationAuthorizationRequest: 'Always', persistMode: 1, autoSync: true, startOnBoot: true, enableHeadless: true)) .then((bg.State state) async { print("[ready] ${state.toMap()}"); if (state.schedule!.isNotEmpty) { bg.BackgroundGeolocation.startSchedule(); } if (state.enabled) { bg.BackgroundGeolocation.setOdometer(HydratedBloc.storage.read("odometer")); } }).catchError((error) { print('[ready] ERROR: $error'); });
// Register headless task
bg.BackgroundGeolocation.registerHeadlessTask(backgroundGeolocationHeadlessTask);
Read what I said again.
Also, I asked a question. Please answer my question.
I'm reviewing the plugin documentation and making the necessary changes in hopes that it will work even when the app is terminated.
I asked you a question. Please answer it.
On an unrelated note, where did you get the idea to use these options?
forceReloadOnBoot: true, forceReloadOnGeofence: true, forceReloadOnHeartbeat: true,
I also said:
If I were you, I’d disable everywhere that . setOdometer(0.0) is called, to determine if that is the source of my problem.
COMMENT THOSE LINES OUT AND TEST. I didn’t say change those lines and ask more questions.. I said remove those lines
bg.BackgroundGeolocation.setOdometer(HydratedBloc.storage.read("odometer"))
That would not be a smart thing to do. The plug-in already stores its odometer in persistent storage.
This issue is stale because it has been open for 30 days with no activity.
This issue was closed because it has been inactive for 14 days since being marked as stale.