flutter_reactive_ble can't be used using flutter_isolate?
Hey, I'm trying to run code that uses the flutter_reactive_ble library in an isolate using your plugin. However, the same code - that runs perfectly fine in the foreground - doesn't run in an isolate. When I went through the code with a debugger I saw that the package functionality is not provided.
The first thing I'm doing after initializing my BLEManager is to check the ble state of my own smartphone. The state is returned as unknown. Any ideas on how to make this package run using flutter_isolate?
thanks and best regards!
Is this on Android? If flutter_reactive_ble is like flutter_blue, it might not be possible to use with flutter_isolate (see https://github.com/rmawatson/flutter_isolate/issues/71).
Basically anything running under a Flutter isolate does not have an attached Activity, so any Flutter plugin that assumes the existence of an Activity just won't work.
Hey, thanks for the quick reply!
No, it happens on iOS. However, I figured out that it's just the BLE state of the smartphone that cannot be discovered and therefore remains unknown. I can ignore it, since the rest of the code runs in the isolate.
Hi @nmfisher ,
I'm not 100% sure, but for it seems a bit like flutter_isolate doesn't run properly in the background. I upgraded Xcode to version 13.1, because it was necessary to be able to work with flutter_reactive_ble. Since then I get the following warning:
[BackgroundTask] Background Task 2 ("Flutter debug task"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination. Remember to call UIApplication.endBackgroundTask(:) for your task in a timely manner to avoid this._
I know that this is a message from the debugger that doesn't appear in the release version.
Two other things happen to me. Number one is that I'm not able to spawn new isolates from within a running isolate. Every object in that new spawned isolate stays null and cannot properly initialized. The second thing is that the app stops executing, and only continues working when I put the app in the foreground again.
My device is an iPhone X with iOS 15.0.2 installed. Btw, on Android everything runs smoothly.
Thanks @ahoelzemann, are you able to provide an example repository that demonstrates the bug?
Thanks for the quick reply. I can't give you access to the complete application, since it's a private repository, but I created another one with my two dart files that are important.
https://github.com/ahoelzemann/isolate_example
LandingScreen.dart:
Line 823/824: spawns the isolate and is followed by the listener that listens on the port for messages. Line 36: defines the method isolate1 which contains just one line of code that triggers an upload of data from a smartwatch to my smartphone.
BTExperimental.dart
Line 700: stopRecordingAndUpload() is executed in the background. This method creates an object of my BLEManager and executes all necessary methods to upload data. At the end of the method my data gets uploaded to a webserver.
The complete procedure takes up to 45 minutes, therefore I need to execute it in the background.
Thanks, I'll take a look over the next few days.
@nmfisher I digged a bit deeper and the problem that objects and variables were set to null was related to a bug in my code for discovering BLE devices - reported here https://github.com/PhilipsHue/flutter_reactive_ble/issues/446.
However, the isolate still stops working when the app is put in the background and my device gets disconnected.
I now spawn a main isolate (line 935 in LandingScreen.dart). This main isolate then spawns a worker isolate that deals with the file upload.
I have a listener set that listens to disconnections from the device (line 742, BTExperimental.dart) and notifies the main isolate to kill the worker isolate and spawn a new one that starts over the upload process (line 44, LandingScreen.dart).
Whenever this happens and the app is in the background, the main isolate is supposed to spawn a new worker.
The following log shows the problem a bit (take a closer look on the time stamp). A respawn should normally be executed after one minute.
Important are the following two lines:
At 14:33:49.407507+0100 the device has been disconnected (app is in the background), Then the app is in hibernate mode, even though the main isolate should continue running and spawn a new one after one minute.
At 14:37:07.796322+0100 I put the app again in the foreground and the execution continues immediately.
However the code runs fine, as long as the app stays in the foreground. It also terminates without any problems when the app is in the background and the device doesn't get disconnected (and therefore I don't need to spawn a another worker isolate).
14:33:40.181088+0100 Runner flutter: startUpload()
14:33:40.181220+0100 Runner flutter: =4
14:33:40.181313+0100 Runner flutter: >
14:33:42.183798+0100 Runner flutter: ble start upload command done /////////////
14:33:42.185045+0100 Runner flutter: Status:Instance of '_ControllerStream<ConnectionStateUpdate>'
14:33:42.186110+0100 Runner flutter: WAITING FOR 4 FILES, THIS WILL TAKE SOME MINUTES ...
14:33:42.687681+0100 Runner flutter: 1 Start uploading ///////////////
14:33:42.761694+0100 Runner flutter: Saving: d202111171019.bin
14:33:45.833573+0100 Runner Received configuration update from daemon (initial)
14:33:49.407386+0100 Runner flutter: ConnectionState for device 59A31B6A-36F9-8D73-9255-60CDE3C0261B : DeviceConnectionState.disconnected
14:33:49.407507+0100 Runner flutter: LISTENER LISTENS TO CHANGE
14:33:49.414572+0100 Runner flutter: BLE Connection closed - Killing the Isolate and spawning a new one.
14:33:49.415595+0100 Runner flutter: Error unsubscribing from notifications: PlatformException(reactive_ble_mobile.Central.(unknown context at $1013570e4).Failure:1, The operation couldn’t be completed. (reactive_ble_mobile.Central.(unknown context at $1013570e4).Failure error 1.), {}, null)
14:33:49.424858+0100 Runner {"msg":"CLLocationManager", "event":"activity", "_cmd":"dealloc", "self":"0x2827be600"}
14:33:49.425188+0100 Runner {"msg":"state transition", "event":"state_transition", "state":"LocationManager", "id":"0x2827be600", "property":"requestingLocation", "old":0, "new":0}
14:33:49.425380+0100 Runner {"msg":"state transition", "event":"state_transition", "state":"LocationManager", "id":"0x2827be600", "property":"requestingRanging", "old":0, "new":0}
14:33:49.426327+0100 Runner {"msg":"state transition", "event":"state_transition", "state":"LocationManager", "id":"0x2827be600", "property":"updatingRanging", "old":0, "new":0}
14:33:49.426455+0100 Runner {"msg":"invalidating client", "client":"0x125e821d0"}
14:33:49.426688+0100 Runner {"msg":"invalidating client", "client":"0x125e821d0"}
14:33:49.427892+0100 Runner {"msg":"state transition", "event":"state_transition", "state":"LocationManager", "id":"0x2827be600", "property":"lifecycle", "old":"0x280e956c0", "new":"0x0"}
14:33:49.432038+0100 Runner {"msg":"client about to be destroyed", "client":"0x125e821d0"}
14:33:53.712428+0100 Runner {"msg":"CLLocationManager", "event":"activity", "_cmd":"onDidBecomeActive:", "self":"0x2827a3830", "notification":"NSConcreteNotification 0x2825aad80 {name = UIApplicationDidBecomeActiveNotification; object = <UIApplication: 0x125d062d0>}"}
14:33:53.712692+0100 Runner {"msg":"CLLocationManager", "event":"activity", "_cmd":"onDidBecomeActive:", "self":"0x2827b61e0", "notification":"NSConcreteNotification 0x2825aad80 {name = UIApplicationDidBecomeActiveNotification; object = <UIApplication: 0x125d062d0>}"}
14:37:06.132174+0100 Runner [de.activate.tractomove] Getting pending notification requests (async)
14:37:06.188133+0100 Runner [de.activate.tractomove] Getting pending notification requests (async)
14:37:06.188409+0100 Runner [de.activate.tractomove] Getting pending notification requests (async)
14:37:06.271178+0100 Runner [de.activate.tractomove] Got 0 pending notification [ hasCompletionHandler: 1 ]
14:37:06.340307+0100 Runner [de.activate.tractomove] Got 0 pending notification [ hasCompletionHandler: 1 ]
14:37:06.353213+0100 Runner [de.activate.tractomove] Got 0 pending notification [ hasCompletionHandler: 1 ]
14:37:06.409303+0100 Runner #Warning Connection interrupted!
14:37:06.456461+0100 Runner {"msg":"CLConnection::handleInterruption", "event":"activity"}
14:37:06.468735+0100 Runner {"msg":"CLClientInterruptionHandler", "event":"activity", "client":"0x125e961f0"}
14:37:06.468940+0100 Runner {"msg":"Sending cached messages to daemon", "event":"activity"}
14:37:06.469192+0100 Runner [de.activate.tractomove] Getting notification categories (async)
14:37:06.627194+0100 Runner Will expire BGTask activities: {(
)}
14:37:06.630630+0100 Runner Will expire activities: {(
)}
14:37:06.631259+0100 Runner Calling expiration handlers for activities: {(
)}
14:37:06.631489+0100 Runner Calling expiration handlers for tasks: {(
)}
14:37:07.796322+0100 Runner flutter: ble is available.
14:37:07.796401+0100 Runner flutter: scanning for devices
14:37:08.095741+0100 Runner flutter: Bangle.js 834b
14:37:08.095995+0100 Runner flutter: [144, 5, 0, 0, 0, 0, 0, 0, 0, 0]
14:37:08.096240+0100 Runner flutter: \^E
14:37:08.097269+0100 Runner flutter: trying to connect....
14:37:08.097842+0100 Runner flutter: Start connecting to 59A31B6A-36F9-8D73-9255-60CDE3C0261B
14:37:08.863404+0100 Runner [VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: Bad state: Future already completed
#0 _AsyncCompleter.complete (dart:async/future_impl.dart:45)
#1 BluetoothManager._checkIfBLAndLocationIsActive.<anonymous closure> (package:trac2move/ble/BTExperimental.dart:141)
<asynchronous suspension>
14:37:09.833574+0100 Runner flutter: ConnectionState for device 59A31B6A-36F9-8D73-9255-60CDE3C0261B : DeviceConnectionState.connected
14:37:09.833678+0100 Runner flutter: connected! now discovering characteristics
14:37:09.834312+0100 Runner flutter: LISTENER LISTENS TO CHANGE
14:37:11.836402+0100 Runner flutter: not Sending
14:37:12.340251+0100 Runner flutter: checkingOsVersion
14:37:12.940493+0100 Runner flutter: setting time
14:37:14.953588+0100 Runner flutter: Sending getNumFiles command...
14:37:20.042016+0100 Runner flutter: [115, 116, 97, 114, 116, 85, 112, 108, 111, 97, 100, 40, 41, 13, 10] //////////////
14:37:20.042154+0100 Runner flutter: startUpload()
14:37:20.042340+0100 Runner flutter:
14:37:20.058201+0100 Runner flutter: [61, 52, 13, 10, 62] //////////////
14:37:20.058924+0100 Runner flutter: startUpload()
14:37:20.059098+0100 Runner flutter: =4
@nmfisher , have you had time to look into the problem further?
@ahoelzemann - if I'm reading your issue correctly, you're saying that a running isolate cannot spawn a child isolate when the app is running in the background on iOS?
@nmfisher no, not exactly. Sorry for the misunderstanding. My very long running (up to 2 hours) isolate pauses. The function my isolates call contains several other function calls. I'm using BLE to connect to a smartwatch and upload data from the smartwatch to my phone. After this I want to upload my data to a server.
However, sometimes the isolates pauses after executing the data upload from the watch to the phone and doesn't execute the server upload.