问题
I have an app uploading joystick position data to a webserver using an API call.
This method gets called when a joystick is moved. It stops any previously running isolate and starts a new isolate if the joystick is not in the centre.
void onJoystickMoved(double angle, double distance) {
stopIsolate();
if(distance > 0.06){
startIsolate(JoystickPosition.fromDistanceAndRadius(distance, angle));
}
}
The isolate start and stop methods
Future<void> startIsolate(JoystickPosition position) async {
isolate = await Isolate.spawn(uploadJoystickPosition, position);
}
void stopIsolate() {
if (isolate != null) {
debugPrint("Stopping isolate");
isolate.kill();
isolate = null;
}
}
uploadJoystickPosition method (the method in the isolate):
void uploadJoystickPosition(JoystickPosition position){
Timer.periodic(new Duration(seconds: 1), (Timer t) {
DataModel dataModel = DataModel(1, getTimeInSeconds());
dataModel.joystickPosition = position;
debugPrint("Distance: ${position.distance}");
uploadData(dataModel).then(uploadResponse, onError: uploadError);
});
}
Trouble is the uploadJoystickPosition keeps uploading old positions of the joystick along with new positions. I am assuming this is because the timer keeps running even when the isolate is killed.
Questions:
- Why does my timer keep going(and uploading) even after I kill the isolate?
- How do I get my timer to stop when I kill the isolate its running in?
回答1:
As I noted in a comment, your example code has:
Future<void> startIsolate() async {
stopIsolate();
isolate =
await Isolate.spawn(isolateMethod, DateTime.now().toIso8601String());
}
void stopIsolate() {
if (isolate != null) {
debugPrint("Stopping isolate");
isolate.kill();
isolate = null;
}
}
Nothing stops startIsolate
from being called while another call to startIsolate
is already in progress. Therefore your problem is not that killing an isolate doesn't stop its Timer
s, it's that you leak isolates and prevent yourself from killing them. You need to add a guard to avoid spawning a new isolate while another creation request is in progress. A bool
would be sufficient:
bool isStartingIsolate = false;
Future<void> startIsolate() async {
if (isStartingIsolate) {
// An isolate is already being spawned; no need to do anything.
return;
}
stopIsolate();
isStartingIsolate = true;
try {
isolate =
await Isolate.spawn(isolateMethod, DateTime.now().toIso8601String());
} finally {
isStartingIsolate = false;
}
}
A different approach, if you want to wait for the pending startIsolate
call to finish before processing any new ones:
Future<void> pendingStartIsolate;
Future<void> startIsolate() async {
while (pendingStartIsolate != null) {
await pendingStartIsolate;
}
stopIsolate();
try {
pendingStartIsolate =
Isolate.spawn(isolateMethod, DateTime.now().toIso8601String());
isolate = await pendingStartIsolate;
} finally {
pendingStartIsolate = null;
}
}
来源:https://stackoverflow.com/questions/63398204/timer-inside-flutter-isolate-not-stopping-when-isolate-is-killed