fluttercommunity / flutter_workmanager

A Flutter plugin which allows you to execute code in the background on Android and iOS.
825 stars 247 forks source link

Documentation - How to communicate between the background task (isolate) and other widgets #541

Open jonathanMNg opened 4 months ago

jonathanMNg commented 4 months ago

Version 0.5.0

Describe the error Hi, I'm trying to execute a Bloc event with the workmanager callbackDispatcher(). However, because the function callbackDispatcher itself is an Isolate, it can't modify the variables of the main execution. My workaround is to use SendPort and ReceivePort.

In the main.dart:

@pragma('vm:entry-point')
void callbackDispatcher() {
  Workmanager().executeTask((task, inputData) {
    if(task == 'sleep-timer') {
      final SendPort? send = IsolateNameServer.lookupPortByName('sleep_timer_send_port');
      if (send != null) {
        send.send(inputData);
      }
    }
    return Future.value(true);
  });
}

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Workmanager().initialize(callbackDispatcher,isInDebugMode: true);
  runApp(const MyApp());
}

In the timer_bloc.dart:


 TimerBloc() : super(TimerInitial()) {

    on<Start>((event, emit) async {
      Workmanager().cancelByTag('sleep-timer-tag');
      final ReceivePort port = ReceivePort();
      _bindBackgroundIsolate(port);
      await Workmanager().registerOneOffTask(
          UniqueKey().toString(),
          'sleep-timer',
          tag: 'sleep-timer-tag',
          initialDelay: event.duration,
          inputData: {"executeTask": true},
          existingWorkPolicy: ExistingWorkPolicy.replace
      );
  });

  void _bindBackgroundIsolate(ReceivePort port) {
    final isSuccess = IsolateNameServer.registerPortWithName(port.sendPort, 'sleep_timer_send_port');
    if (!isSuccess) {
      _unbindBackgroundIsolate('sleep_timer_send_port');
      _bindBackgroundIsolate(port);
      return;
    }
    port.listen((dynamic data) async {
      // final isDone = data;
      if(data != null && data['executeTask']) {
        do_other_task();
      }
    });
  }
  void _unbindBackgroundIsolate(String name) {
    IsolateNameServer.removePortNameMapping(name);
  }
}

I think that adding this to the documentation would help others. FYI, I copied that code from this project flutter_downloader Thanks,

SEGVeenstra commented 4 days ago

I can imagine this being a very common use-case when using background tasks. At least I found out I needed this within the first week of using background tasks.

Not sure if the documentation would require a full guide or maybe just a section with some references to this issue for example, as this is more about how Isolates work then about this package specifically.

Anyway, I'm very grateful that you shared this!