【问题标题】:Dart Isolate utilizing Timer periodic doesn't stopDart Isolate 利用 Timer 周期不会停止
【发布时间】:2021-04-04 21:24:51
【问题描述】:

我在我的 Flutter 应用程序中调用了以下 Dart Isolate,它每 7 秒通过 _checkTimer 方法运行和处理一项任务。这对于我需要每隔一段时间运行的后台任务非常方便。

import 'dart:async';
import 'dart:isolate';

class TimeTrackingDigester with ChangeNotifier {
  Isolate _isolate;
  static int _counter = 0;
  ReceivePort _receivePort;

  void startIsolate() async {
    print('**** time tracking digester = startIsolate');

    _receivePort = ReceivePort();
    _isolate = await Isolate.spawn(
      _checkTimer,
      _receivePort.sendPort,
    );
    _receivePort.listen(
      _handleMessage,
      onDone: () {
        //@TODO this never fires
        print('done!');
      },
    );
  }

  void stopIsolate() => _stop();

  static void _checkTimer(SendPort sendPort) async {
    print('**** time tracking digestoer = checkTimer');
    Timer.periodic(
      const Duration(seconds: 7),
      (Timer t) async {
        _counter++;
        print('**** time tracking digestoer = $_counter');
        
        var task = 'result from some action here';

        sendPort.send(task);
      },
    );
  }

  void _handleMessage(dynamic data) {
    print('**** time tracking digestoer = handleMessage');
    print('RECEIVED: $data');
  }

  //@TODO this is not stopping the isolate
  void _stop() {
    print('**** time tracking digestoer = stop');
    print(_isolate);

    if (_isolate != null) {
      print('* isolate is not null');
      // setState(() {
      //     _running = false;
      //
      // });
      _receivePort.close();
      _isolate.kill(priority: Isolate.immediate);
      _isolate = null;
    }
  }
}

我的第一个问题是,一旦隔离启动,我调用 stopIsolate 方法来停止隔离,但它不会触发 close()/kill() 调用,因为 _isolate 被认为是 null。据我所知,_isolate 始终是null,我错过了在以下节中实际设置_isolate 的步骤:

if (_isolate != null) {
    print('* isolate is not null');
    // setState(() {
    //     _running = false;
    //
    // });
    _receivePort.close();
    _isolate.kill(priority: Isolate.immediate);
    _isolate = null;
 }

我的第二个问题是,如果我忽略 null 检查,而只是调用 close()/kill() 方法,则会引发以下异常:

NoSuchMethodError:在 null 上调用了方法“close”。我/颤动 (15558):接收器:空 I/颤振 (15558):尝试调用:close()

我想要完成的最终结果:当我想停止 Isolate 时,它​​会完全停止后续的 _checkTimer 方法,并解决 _isolate 未正确设置以触发 null 检查正确。

【问题讨论】:

标签: flutter dart


【解决方案1】:

我测试了你的代码,它可以成功地停止隔离。 请确保您使用的是相同的 TimeTrackingDigester 实例,这样 _isolate 就不会是 null

运行此示例应用程序。

import 'dart:async';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(fontFamily: 'Roboto'),
      home: SampleIsolate(),
    );
  }
}

class SampleIsolate extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => TimeTrackingDigester(),
      child: Builder(
        builder: (context2) => Scaffold(
          body: Center(
            child: RaisedButton(
              onPressed: () {
                // Will get the TimeTrackingDigester created in "create: (_) => ..."
                final digester = Provider.of<TimeTrackingDigester>(
                  context2,
                  listen: false,
                );
                if (digester.isStarted) {
                  digester.stopIsolate();
                } else {
                  digester.startIsolate();
                }
              },
              child: const Text('Start / Stop'),
            ),
          ),
        ),
      ),
    );
  }
}

class TimeTrackingDigester with ChangeNotifier {
  Isolate _isolate;
  static int _counter = 0;
  ReceivePort _receivePort;

  bool get isStarted => _isolate != null;

  void startIsolate() async {
    print('**** time tracking digester = startIsolate');

    _receivePort = ReceivePort();
    _isolate = await Isolate.spawn(
      _checkTimer,
      _receivePort.sendPort,
    );
    _receivePort.listen(
      _handleMessage,
      onDone: () {
        //@TODO this never fires
        print('done!');
      },
    );
  }

  void stopIsolate() => _stop();

  static void _checkTimer(SendPort sendPort) async {
    print('**** time tracking digestoer = checkTimer');
    Timer.periodic(
      const Duration(seconds: 7),
      (Timer t) async {
        _counter++;
        print('**** time tracking digestoer = $_counter');

        var task = 'result from some action here';

        sendPort.send(task);
      },
    );
  }

  void _handleMessage(dynamic data) {
    print('**** time tracking digestoer = handleMessage');
    print('RECEIVED: $data');
  }

  //@TODO this is not stopping the isolate
  void _stop() {
    print('**** time tracking digestoer = stop');
    print(_isolate);

    if (_isolate != null) {
      print('* isolate is not null');
      // setState(() {
      //     _running = false;
      //
      // });
      _receivePort.close();
      _isolate.kill(priority: Isolate.immediate);
      _isolate = null;
    }
  }
}

【讨论】:

  • 请三重检查,当您停止隔离时,代码的计时器部分也会停止。即使隔离在我身边停止,我看到计时器仍在继续。
  • @ZachSmith 真的吗?计时器停在我身边。我正在使用 iOS 模拟器(iPhone SE 第 1 代 14.2)、Dart 版本 2.10.4 和 Flutter 1.22.5(通道稳定版)。
猜你喜欢
  • 1970-01-01
  • 2021-07-13
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 2017-02-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多