Timer inside flutter isolate not stopping when isolate is killed

懵懂的女人 提交于 2021-01-28 09:53:41

问题


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:

  1. Why does my timer keep going(and uploading) even after I kill the isolate?
  2. 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 Timers, 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!