background_locator_fixed
background_locator_fixed copied to clipboard
[Question] How to correctly stop background locator & release its memory usage?
I my app, user can turn on/off background location through setting using a toggle.
When the toggle switch to off, I called
await BackgroundLocator.unRegisterLocationUpdate();
When the toggle switch to on, I called
static Future<void> startBackgroundTracking() async {
Mutex().protect(() async {
await init();
SharedPreferences prefs = await SharedPreferences.getInstance();
BackgroundLocator.registerLocationUpdate(
callbackFromBackground,
initDataCallback: {},
initCallback: initBackgroundTracking,
autoStop: false,
iosSettings: const IOSSettings(accuracy: LocationAccuracy.NAVIGATION, distanceFilter: 1),
androidSettings: AndroidSettings(
accuracy: LocationAccuracy.NAVIGATION,
distanceFilter: 0,
androidNotificationSettings: AndroidNotificationSettings(...),
),
);
});
}
Where init() is:
static Future<void> init() async {
_port = ReceivePort();
if (IsolateNameServer.lookupPortByName(_isolateName) != null) {
IsolateNameServer.removePortNameMapping(_isolateName);
}
_port.listen((dynamic data) async {
// TODO: Listen from background and do something with it
});
await BackgroundLocator.initialize();
}
Somehow, the memory keep increasing when ever I call startBackgroundTracking(), even though I have already unregister BackgroundLocator
Here is the snapshots of memory usage, small bumps are when I turn on the background tracking
Btw, somehow it sends the location multiple times at the same time
D/plugin ( 1455): sendLocationEvent {callback=43457826900314605, location={altitude=62.10000228881836, heading=271.16943, latitude=37.5016455, accuracy=20.0, speed_accuracy=0.0, time=1.659818976698E12, is_mocked=false, speed=0.0070893257, longitude=127.0342517}}
D/plugin ( 1455): sendLocationEvent {callback=43457826900314605, location={altitude=62.10000228881836, heading=271.16943, latitude=37.5016455, accuracy=20.0, speed_accuracy=0.0, time=1.659818976698E12, is_mocked=false, speed=0.0070893257, longitude=127.0342517}}
D/plugin ( 1455): sendLocationEvent {callback=43457826900314605, location={altitude=62.10000228881836, heading=271.16943, latitude=37.5016455, accuracy=20.0, speed_accuracy=0.0, time=1.659818976698E12, is_mocked=false, speed=0.0070893257, longitude=127.0342517}}
D/plugin ( 1455): sendLocationEvent {callback=43457826900314605, location={altitude=62.10000228881836, heading=271.16943, latitude=37.5016455, accuracy=20.0, speed_accuracy=0.0, time=1.659818976698E12, is_mocked=false, speed=0.0070893257, longitude=127.0342517}}
D/plugin ( 1455): sendLocationEvent {callback=43457826900314605, location={altitude=62.10000228881836, heading=271.16943, latitude=37.5016455, accuracy=20.0, speed_accuracy=0.0, time=1.659818976698E12, is_mocked=false, speed=0.0070893257, longitude=127.0342517}}
D/plugin ( 1455): sendLocationEvent {callback=43457826900314605, location={altitude=62.10000228881836, heading=271.16943, latitude=37.5016455, accuracy=20.0, speed_accuracy=0.0, time=1.659818976698E12, is_mocked=false, speed=0.0070893257, longitude=127.0342517}}
D/plugin ( 1455): sendLocationEvent {callback=43457826900314605, location={altitude=62.10000228881836, heading=354.10712, latitude=37.5016457, accuracy=20.0, speed_accuracy=0.0, time=1.65981898171E12, is_mocked=false, speed=0.0034208533, longitude=127.0342518}}
D/plugin ( 1455): sendLocationEvent {callback=43457826900314605, location={altitude=62.10000228881836, heading=354.10712, latitude=37.5016457, accuracy=20.0, speed_accuracy=0.0, time=1.65981898171E12, is_mocked=false, speed=0.0034208533, longitude=127.0342518}}
D/plugin ( 1455): sendLocationEvent {callback=43457826900314605, location={altitude=62.10000228881836, heading=354.10712, latitude=37.5016457, accuracy=20.0, speed_accuracy=0.0, time=1.65981898171E12, is_mocked=false, speed=0.0034208533, longitude=127.0342518}}
D/plugin ( 1455): sendLocationEvent {callback=43457826900314605, location={altitude=62.10000228881836, heading=354.10712, latitude=37.5016457, accuracy=20.0, speed_accuracy=0.0, time=1.65981898171E12, is_mocked=false, speed=0.0034208533, longitude=127.0342518}}
D/plugin ( 1455): sendLocationEvent {callback=43457826900314605, location={altitude=62.10000228881836, heading=354.10712, latitude=37.5016457, accuracy=20.0, speed_accuracy=0.0, time=1.65981898171E12, is_mocked=false, speed=0.0034208533, longitude=127.0342518}}
D/plugin ( 1455): sendLocationEvent {callback=43457826900314605, location={altitude=62.10000228881836, heading=354.10712, latitude=37.5016457, accuracy=20.0, speed_accuracy=0.0, time=1.65981898171E12, is_mocked=false, speed=0.0034208533, longitude=127.0342518}}
Hi @hieudz, Interesting problem, I'm actually in vacations so I won't have time to investigate yet, I'll see when I can do something about it. It's kind of a serious problem though, so if someone feels like investigating, feel free to do so. I'll add a new flair for these kind of problems with community help wanted.
I haven't figure out the detail why this happened, but I know why my app generate multiple callback error.
Basically, I triggered the startBackgroundTracking() twice within a short period (e.g. 0.0001s), which somehow causes race condition in the plug in. I suspect that background_locator_2 just protect this using
if (IsolateHolderService.isServiceRunning) {
// The service is running already
Log.d("BackgroundLocatorPlugin", "Locator service is already running")
result?.success(true)
return
}
but it seems to be not enough for immediatel triggers like this.
Temp Solution: We can use mutex and wait for the operations to complete. It will stop sending multiple callback, but it will still have memory leak
P/s: I tried to used Mutex() as above, but I used it wrongly (I should've created Mutex mutex = Mutex()
then called mutex.protect(...)
)
Update: This also happened to the example app. Just turn it on/off multiple times, we can observe the memory leak
Update: Narrowed down the problem, the memory leak disappeared when I comment out
IsolateHolderService.backgroundEngine?.dartExecutor?.executeDartCallback(args)
at IsolateHolderExtension.kt:51
Update: Problem founded, created by this commit https://github.com/Yukams/background_locator_fixed/commit/5d214753366c5272406f4d89f1c0d65b92e70e86
Since we create a new FlutterEngine everytime without releasing it later(?), it causes memory leak
IsolateHolderService.backgroundEngine = null
+ IsolateHolderService.backgroundEngine = FlutterEngine(context)
Update: Here is my pull request https://github.com/Yukams/background_locator_fixed/pull/30
I'll update it asap thank you for your contribution !
thank you so much for your contribution.
additionally, I'm using your fixed branch on flutter 3.0.5 only on android.
until now I never stopped the service but now I need it to stop when the app is terminated.
but now every time I terminate the app and reopen I get doubled callbacks like this:
this is what I do when I reopen the app: if (!isUpdated || !isServiceRunning) { await initBackgroundLocator(); await _registerLocator(staticRepository); }