当隔离被杀死时,抖动隔离内的计时器不会停止

Timer inside flutter isolate not stopping when isolate is killed

我有一个应用程序使用 API 调用将操纵杆位置数据上传到网络服务器。

移动操纵杆时会调用此方法。如果操纵杆不在中心,它会停止任何先前的 运行 隔离并启动新的隔离。

void onJoystickMoved(double angle, double distance) {
stopIsolate();
if(distance > 0.06){
  startIsolate(JoystickPosition.fromDistanceAndRadius(distance, angle));
}
}

隔离启动和停止方法

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方法(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);
   });
}

问题在于 uploadJoystickPosition 不断上传操纵杆的旧位置和新位置。我假设这是因为计时器保持 运行 即使隔离被杀死。

问题:

  1. 为什么我的计时器在我杀死隔离后仍继续运行(并上传)?
  2. 当我杀死其 运行 中的隔离物时,如何让我的计时器停止?

正如我在评论中指出的那样,您的示例代码具有:

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;
  }
}

当另一个对 startIsolate 的调用已经在进行时,没有什么能阻止 startIsolate 被调用。因此,你的问题不是杀死一个 isolate 并不能阻止它的 Timers,而是你 leak isolates 并阻止你自己杀死它们。您需要添加一个守卫,以避免在另一个创建请求正在进行时产生一个新的隔离。 bool 就足够了:

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;
  }
}

一种不同的方法,如果您想等待挂起的 startIsolate 调用完成后再处理任何新调用:

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;
  }
}

查看插件 easy_isolate,它提供了一种简单的方法来使用 isolates 和已经完成的安全检查和其他很酷的功能,还有一个很好解释的文档。

https://pub.dev/packages/easy_isolate