Flutter 如何将消息传递给 Android AlarmManager 创建的隔离区

Flutter how to pass messages to the isolate created by Android AlarmManager

我正在使用 Android AlarmManger 在特定日期和时间设置 oneShotAt 闹钟。一旦闹钟被激活,我就在 FlutterRingtonePlayer 的帮助下播放循环声音。

class _MyHomePageState extends State<MyHomePage> {
  TimeOfDay _time = TimeOfDay.now();
  DateTime _date = DateTime.now();
  final int helloAlarmID = 0;

  static playLocalAsset() {
    final DateTime now = DateTime.now();
    final int isolateId = Isolate.current.hashCode;
    print("[$now] Hello, world! isolate=${isolateId}");
    FlutterRingtonePlayer.playAlarm(looping: true);
  }

  static stopLocalAsset() {
    print("TEST");
    FlutterRingtonePlayer.stop();
  }
  void stopMusic() async {
    AndroidAlarmManager.oneShot(Duration(seconds: 0), helloAlarmID, stopLocalAsset);
  }
  //Date and Time Picking
  Future<Null> selectTime(BuildContext context) async {
    await selectDate(context);
    _time = await showTimePicker(context: context, initialTime: _time);
    _date = DateTime(_date.year, _date.month, _date.day, _time.hour, _time.minute);
    print(_date);
    await AndroidAlarmManager.oneShotAt(_date, helloAlarmID, playLocalAsset); //ALARM SET HERE
  }

  Future<Null> selectDate(BuildContext context) async {
    _date = await showDatePicker(context: context, initialDate: _date, firstDate: _date, lastDate: DateTime(2222));
  }

所以闹钟设置得很完美,它会在准确的时间响起。但是,当我想停止音乐时,却无法停止。所以我不得不使用 AlarmManager 的另一个 oneShot 来访问隔离并停止音乐,如上面的代码所示。这样就停止了音乐,但是光是停止音乐就需要3秒多的时间。

我的问题是,如何让 AlarmManger 在按下停止按钮后立即停止播放音乐。

谢谢, 杰克

编辑:删除了保留用于测试的行。

所以在网上搜索后,我终于找到了一种在按下后立即停止播放器的方法。

由于AlarmManger创建了一个隔离,你必须在AlarmMangercallback函数中创建一个接收端口。在我的例子中是static playLocalAsset()

static playLocalAsset() {
    ReceivePort rcPort = new ReceivePort();
    IsolateNameServer.registerPortWithName(rcPort.sendPort, portName);
    rcPort.listen((v) {
      FlutterRingtonePlayer.stop();
    });
    final DateTime now = DateTime.now();
    final int isolateId = Isolate.current.hashCode;
    print("[$now] Hello, world! isolate=${isolateId}");
    FlutterRingtonePlayer.playAlarm(looping: true);
  }

在所有函数之外创建一个端口名(比如一个全局变量),如

const String portName = "ConnectingIsolate";

现在在您的停止按钮函数中创建一个 SendPort,它将发送到您已在全局声明的端口名。在我的例子中,最后的 stopLocalAsset() 看起来像

void stopMusic() {
    SendPort sendPort = IsolateNameServer.lookupPortByName(portName);
    sendPort.send("Abcd");
  }

所以,基本上,当您通过 SendPort 发送内容时,接收端口(处于隔离状态)将监听并执行您在 rcport.listen 函数中提供的任何操作,这在我的案例是停止播放器。

希望这对您有所帮助。