0

我试图使用插件Android 警报管理器在后台执行计时器和代码,但不能真正让它正常工作。如果我将“print(”v“)”之类的东西设置为回调 - 一切正常,但是当我尝试做一些额外的事情时,它就不起作用了。

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

class MyApp extends StatefulWidget {
  _MyAppState createState() => _MyAppState();
}



startTimer(sendport) async {
  await AndroidAlarmManager.oneShot(
      Duration(seconds: 60), 0, timerCallback(sendport),
      wakeup: true, exact: true);
}

timerCallback(sendport) {
  sendport.send("DONE");
}

class _MyAppState extends State<MyApp> {
  ReceivePort receivePort = ReceivePort();
  SendPort sendport;

  @override
  void initState() {
    super.initState();
    AndroidAlarmManager.initialize();
    receivePort.listen((v) {
      print(v);
    });
  }

  @override
  Widget build(BuildContext context) {
    RaisedButton(
      onPressed: startTimer(sendport),
      child: Text("Start"),
    );
  }
}

我希望该代码在 1 分钟后发送消息,而不是在执行后立即收到消息并得到 Error "/flutter (11424): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: 'dart: ui/plugins.dart':断言失败:第 62 行:'':'callback' 不能为空。”

4

1 回答 1

0

在问题代码中,startTimer( )在设置 oneShot 时调用timerCallup (sendPort),因此它会立即发生。

oneShot调用所需的timerCallback函数不带任何参数。当timerCallback在闹钟时间运行时,它在“隔离”的上下文中运行,这意味着它与应用程序的其余部分隔离。常量似乎可以访问,但变量值不是。timerCallback函数可以通过端口与您的应用程序通信以交换信息,并且可以使用有限的 API 与系统通信,但仅此而已。查看有关隔离的文档以获取详细信息。

Isolates 可以通过使用IsolateNameServer注册和查找名称来找到彼此

您需要主应用程序和回调隔离都可以看到的端口名称,全局常量似乎可以正常工作。

传递给AlarmManager.oneShot的计时器回调没有参数,因此它需要查找端口名称以找到运行时使用的 SendPort。

设置时为主隔离的 SendPort 注册端口名称 - 您仍然需要MyAppState中的 ReceivePort ,但不需要 SendPort。

下面的代码用一个名字注册接收端口,timerCallback 查找这个名字,然后将消息发送到属于接收端口的发送端口。确实感觉很笨重。

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

const String portName = "MyAppPort";

class MyApp extends StatefulWidget {
    _MyAppState createState() => _MyAppState();
}



startTimer() async {
    await AndroidAlarmManager.oneShot(
        Duration(seconds: 60), 0, timerCallback,
        wakeup: true, exact: true);
}

timerCallback() {
    SendPort sendPort = IsolateNameServer.lookupPortByName(portName);
    if (sendPort != null) {
        sendport.send("DONE");
    }
}

class _MyAppState extends State<MyApp> {
    ReceivePort receivePort = ReceivePort();

    @override
    void initState() {
        super.initState();
        IsolateNameServer.registerPortName(receivePort.sendPort, portName)
        AndroidAlarmManager.initialize();
        receivePort.listen((v) {
            print(v);
        });
    }

    @override
    Widget build(BuildContext context) {
        RaisedButton(
            onPressed: startTimer(),
            child: Text("Start"),
        );
  }
于 2019-05-19T16:48:45.583 回答