<p dir="auto">I think, that the Framework should offer a nice and easy way to offload expensive tasks to some kind of background thread/isolate (maybe something like AsyncTask in Android).</p>
<p dir="auto">I built something for myself since I needed image compression and did not find something easy.<br>
Here is what it looks like using it:</p>
<div class="highlight highlight-source-dart notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// getting the 'site' which is the main interface for 
// offloading expensive tasks. It's named after a &quot;construction site&quot; which has 
// multiple workers.

// it will return a future object which is very convenient to handle
// but it will never ever block the main UI thread with the expensive 
// task below
image = await lime.site.commission(
        /// The very, very expensive function which compresses
        /// images using a dart library
        ImageUtil.compressImage,
       /// you can specify the positional arguments here
        positionalArgs: [_file]
      );"><pre class="notranslate"><span class="pl-c">// getting the 'site' which is the main interface for </span>
<span class="pl-c">// offloading expensive tasks. It's named after a "construction site" which has </span>
<span class="pl-c">// multiple workers.</span>

<span class="pl-c">// it will return a future object which is very convenient to handle</span>
<span class="pl-c">// but it will never ever block the main UI thread with the expensive </span>
<span class="pl-c">// task below</span>
image <span class="pl-k">=</span> <span class="pl-k">await</span> lime.site.<span class="pl-en">commission</span>(
        <span class="pl-c">/// The very, very expensive function which compresses</span>
<span class="pl-c">        /// images using a dart library</span>
<span class="pl-c"></span>        <span class="pl-c1">ImageUtil</span>.compressImage,
       <span class="pl-c">/// you can specify the positional arguments here</span>
<span class="pl-c"></span>        positionalArgs<span class="pl-k">:</span> [_file]
      );</pre></div>
<p dir="auto">Here is the implementation of Site as an example:</p>
<div class="highlight highlight-source-dart notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import 'dart:async';
import 'dart:collection';
import 'dart:isolate';

/// Easy and convenient to use, thread-pool-like implementation for delegating
/// expensive tasks to a pool of isolates
///
/// Just pass the function and the desired params to [commission] and let
/// the site handle everything for you by returning a really parallel computed [Future] object.
/// If the [Site] currently holds a reference to an idle Isolate, then the requested computation
/// wil be delegated to it immediately. Otherwise a new [Isolate] is spawned, if it would
/// not exceed [SiteSetting.workersMax]. If this limit is exceeded has the task to wait
/// until any [Isolate] finishes its work on any other task.
///
/// Idle [Isolates] will die after [SiteSetting.workerTimeout].
class Site {

  /// Controls the whole behaviour of this Site and all its Isolates
  ///
  /// The site will not spawn more Isolates than defined by [SiteSetting.workersMax]
  /// and an idling [Isolate] will die after [SiteSetting.workerTimeout]
  final SiteSetting settings;

  /// Holds a reference to all workers currently alive
  final List&lt;_Worker&gt; _workers = [];

  /// Holds a reference to all jobs waiting for delegation to any
  /// [Isolate]
  final Queue&lt;_Job&gt; _jobs = new Queue();

  /// This controller is used to notify when a [_Job] was finished
  /// ignore: close_sinks
  StreamController streamController = new StreamController.broadcast();

  Site(this.settings);

  /// This will execute the [function] inside another Isolate and conveniently
  /// return a easy to handle [Future]
  ///
  /// Be careful: Isolates are not sharing any memory with each other,
  /// therefore try to pass immutable objects as arguments, because any
  /// transformation by [function] won't be reflected in the calling isolate.
  ///
  /// Spawns a new Isolate if all current Isolates are busy and
  /// [SiteSetting.workersMax] is not yet exceeded.
  ///
  /// Will wait for current working Isolates if [SiteSettings.workersMax] is indeed
  /// exceeded and all other Isolates are busy.
  Future&lt;dynamic&gt; commission(Function function,
      {List positionalArgs: const [], Map namedArgs: const{}}) async {
    BackgroundFunction backgroundFunction = new BackgroundFunction(function,
        positionalArguments: positionalArgs, namedArguments: namedArgs);

    _Job job = new _Job(this, backgroundFunction);
    _jobs.add(job);
    patrol();

    await for (dynamic finished in streamController.stream) {
      if (finished == job) {
        return job.result;
      }
    }
  }

  /// Encourages idle [Isolate]s to take a [_Job] from
  /// the Queue and will spawn new a new [Isolate] if necessary
  ///
  /// This method is automatically called.
  /// I cannot easily image a reason why this should
  /// be called manually!
  patrol() {
    _workers.forEach((worker) =&gt; worker.incite());
    if (_jobs.isNotEmpty) {
      if (_workers.length &lt; settings.workersMax) {
        this._workers.add(
            new _Worker(this)
              ..start()
              ..incite());
        print(&quot;Site: Spawning worker. Total ${_workers.length}&quot;);
      }
    }
  }


  void _reportDeathOf(_Worker worker) {
    this._workers.remove(worker);
    print(&quot;Site: Worker $worker died. Left: ${_workers.length}&quot;);
  }


  /// Will shut down this [Site] and kill all
  /// open resources/[Isolate]s
  ///
  /// You should not use this Site ever again after
  /// calling this method.
  ///
  /// Also make sure to call this method after
  /// the [Site] is not needed anymore.
  void close() {
    this.streamController?.close();
    this.streamController = null;
    this._workers.forEach((worker) =&gt; worker.close());
    this._workers.clear();
  }

  finalize() {
    this.close();
  }
}

/// All preferences for a [Site]
class SiteSetting {

  /// How many worker [Isolates] can be spawned at max?
  final int workersMax;

  /// How long is an [Isolate] allowed to idle, before it is killed?
  final Duration workerTimeout;

  /// Will allow a maximum of 2 background [Isolate]s while
  /// killing idle [Isolate]s after 30 seconds
  static const SiteSetting STANDARD = const SiteSetting(2, const Duration(seconds: 30));

  /// Will allow a maximum of 16 background [Isolate]s while
  /// killing idle [Isolate]s after 5 minutes.
  ///
  /// This is only for heavy multitasking applications.
  /// Not quite sure if Dart is the right language here!
  static const SiteSetting HEAVY = const SiteSetting(16, const Duration(minutes: 5));

  /// Will allow a maximum of 2 background [Isolate] while
  /// killing idle [Isolate]s after 1 second.
  static const SiteSetting LIGHT = const SiteSetting(2, const Duration(seconds: 1));


  const SiteSetting(this.workersMax, this.workerTimeout);
}



/// Manages the connection to a dedicated [Isolate].
///
/// Manages its own [Isolate] and is able
/// to work on [_Job] objects.
class _Worker {

  /// The site this worker belongs to
  Site site;

  /// The workers own [Isolate]
  Isolate _isolate;

  /// Will be used for receiving messages
  /// from [_isolate]
  ReceivePort _receivePort;

  /// Will be used to send messages to
  /// [_isolate]
  ///
  /// This should be null-checked, since
  /// the port is received from the [_isolate]
  /// once it is running
  SendPort _sendPort;

  /// The current job, this Worker is working on,
  /// or null if the Worker is idle.
  _Job _currentJob;

  _Worker(this.site);

  /// Tells whether an [Isolate] is currently attached.
  /// Does NOT tell whether its IDLE or not!
  bool get running {
    return _isolate != null;
  }

  /// Will make this Worker start working on an available job
  /// if it is currently idle!
  void incite() {
    if (_currentJob == null &amp;&amp; site._jobs.isNotEmpty) {
      _currentJob = site._jobs.removeFirst();
      print(&quot;Worker: start workiing on $_currentJob&quot;);
      _startWorking();
    }
  }


  /// Send the [_Job] object [_currentJob] to the Isolate,
  /// which will start working on it.
  void _startWorking() {
    assert(_currentJob != null);
    if(_sendPort!=null){
      print(&quot;Worker: delegating to isolate&quot;);
      _sendPort.send(_currentJob.function);
      print(&quot;Worker: waiting for isolate to finish&quot;);
    }
 }

 /// receives the result for the computation associated with
  /// [_currentJob] and will &quot;finish&quot; the associated future
  /// by assigning the result [x] to it.
  void _receive(dynamic x) {
    assert (_currentJob != null);
    _currentJob.result = x;
    _currentJob = null;
    incite();
  }

  /// Starting the Worker will
  /// spawn the [_isolate] and retrieve the [_sendPort].
  ///
  /// This will also lead in a call to [_startWorking] if
  /// a job is currently assigned.
  Future start() async {
    ReceivePort exitReceiver = new ReceivePort();
    exitReceiver.first.then((x) {
      this.close();
      site._reportDeathOf(this);
    });

    _receivePort = new ReceivePort();

    _WorkDay _workDay = new _WorkDay(site.settings, _receivePort.sendPort);
    _isolate =
    await Isolate.spawn(_entryPoint, _workDay, onExit: exitReceiver.sendPort);

    int counter = 0;
    _receivePort.listen((x) {
      if(counter == 0){
        _sendPort = x;
        if(_currentJob!=null) _startWorking();
      }
      else _receive(x);
      counter ++;
    });


  }


  /// Will kill the [Isolate] and this Worker should
  /// never be used again!
  void close() {
    _isolate?.kill();
    _isolate = null;
    _receivePort?.close();
    _receivePort = null;
    _sendPort = null;
    _currentJob = null;
  }


  /// The entry point of [_isolate].
  static void _entryPoint(_WorkDay workDay) {
    ReceivePort receivePort = new ReceivePort();
    Stream receiveStream = receivePort.timeout(workDay.settings.workerTimeout,
        onTimeout: (EventSink sink) {
          print(&quot;Worker: timed out...&quot;);
          receivePort.close();
        });

    receiveStream.listen((BackgroundFunction backgroundFunction) {
      print(&quot;Worker: working&quot;);
      var result = backgroundFunction();
      workDay.sendPort.send(result);
      print(&quot;Worker: idle&quot;);
    });

    workDay.sendPort.send(receivePort.sendPort);
  }
}


/// The initial object sent to a [Isolate] by a [_Worker]
class _WorkDay {
  final SiteSetting settings;
  final SendPort sendPort;

  _WorkDay(this.settings, this.sendPort);
}



class _Job {
  final Site _site;
  final BackgroundFunction function;
  bool finished = false;
  dynamic _result;

  set result(dynamic result) {
    this._result = result;
    this.finished = true;
    this._site.streamController.add(this);
  }

  dynamic get result {
    return _result;
  }

  _Job(this._site, this.function);
}

class BackgroundFunction {
  final Function function;
  final List positionalArguments;
  final Map namedArguments;

  BackgroundFunction(this.function,
      {this.positionalArguments: const[],
        this.namedArguments: const{}});

  dynamic call() {
    return Function.apply(function, positionalArguments, namedArguments);
  }
}"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s">'dart:async'</span>;
<span class="pl-k">import</span> <span class="pl-s">'dart:collection'</span>;
<span class="pl-k">import</span> <span class="pl-s">'dart:isolate'</span>;

<span class="pl-c">/// Easy and convenient to use, thread-pool-like implementation for delegating</span>
<span class="pl-c">/// expensive tasks to a pool of isolates</span>
<span class="pl-c">///</span>
<span class="pl-c">/// Just pass the function and the desired params to <span class="pl-v">[commission]</span> and let</span>
<span class="pl-c">/// the site handle everything for you by returning a really parallel computed <span class="pl-v">[Future]</span> object.</span>
<span class="pl-c">/// If the <span class="pl-v">[Site]</span> currently holds a reference to an idle Isolate, then the requested computation</span>
<span class="pl-c">/// wil be delegated to it immediately. Otherwise a new <span class="pl-v">[Isolate]</span> is spawned, if it would</span>
<span class="pl-c">/// not exceed <span class="pl-v">[SiteSetting.workersMax]</span>. If this limit is exceeded has the task to wait</span>
<span class="pl-c">/// until any <span class="pl-v">[Isolate]</span> finishes its work on any other task.</span>
<span class="pl-c">///</span>
<span class="pl-c">/// Idle <span class="pl-v">[Isolates]</span> will die after <span class="pl-v">[SiteSetting.workerTimeout]</span>.</span>
<span class="pl-c"></span><span class="pl-k">class</span> <span class="pl-c1">Site</span> {

  <span class="pl-c">/// Controls the whole behaviour of this Site and all its Isolates</span>
<span class="pl-c">  ///</span>
<span class="pl-c">  /// The site will not spawn more Isolates than defined by <span class="pl-v">[SiteSetting.workersMax]</span></span>
<span class="pl-c">  /// and an idling <span class="pl-v">[Isolate]</span> will die after <span class="pl-v">[SiteSetting.workerTimeout]</span></span>
<span class="pl-c"></span>  <span class="pl-k">final</span> <span class="pl-c1">SiteSetting</span> settings;

  <span class="pl-c">/// Holds a reference to all workers currently alive</span>
<span class="pl-c"></span>  <span class="pl-k">final</span> <span class="pl-c1">List</span>&lt;<span class="pl-c1">_Worker</span>&gt; _workers <span class="pl-k">=</span> [];

  <span class="pl-c">/// Holds a reference to all jobs waiting for delegation to any</span>
<span class="pl-c">  /// <span class="pl-v">[Isolate]</span></span>
<span class="pl-c"></span>  <span class="pl-k">final</span> <span class="pl-c1">Queue</span>&lt;<span class="pl-c1">_Job</span>&gt; _jobs <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-c1">Queue</span>();

  <span class="pl-c">/// This controller is used to notify when a <span class="pl-v">[_Job]</span> was finished</span>
<span class="pl-c">  /// ignore: close_sinks</span>
<span class="pl-c"></span>  <span class="pl-c1">StreamController</span> streamController <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-c1">StreamController</span>.<span class="pl-en">broadcast</span>();

  <span class="pl-c1">Site</span>(<span class="pl-c1">this</span>.settings);

  <span class="pl-c">/// This will execute the <span class="pl-v">[function]</span> inside another Isolate and conveniently</span>
<span class="pl-c">  /// return a easy to handle <span class="pl-v">[Future]</span></span>
<span class="pl-c">  ///</span>
<span class="pl-c">  /// Be careful: Isolates are not sharing any memory with each other,</span>
<span class="pl-c">  /// therefore try to pass immutable objects as arguments, because any</span>
<span class="pl-c">  /// transformation by <span class="pl-v">[function]</span> won't be reflected in the calling isolate.</span>
<span class="pl-c">  ///</span>
<span class="pl-c">  /// Spawns a new Isolate if all current Isolates are busy and</span>
<span class="pl-c">  /// <span class="pl-v">[SiteSetting.workersMax]</span> is not yet exceeded.</span>
<span class="pl-c">  ///</span>
<span class="pl-c">  /// Will wait for current working Isolates if <span class="pl-v">[SiteSettings.workersMax]</span> is indeed</span>
<span class="pl-c">  /// exceeded and all other Isolates are busy.</span>
<span class="pl-c"></span>  <span class="pl-c1">Future</span>&lt;<span class="pl-c1">dynamic</span>&gt; <span class="pl-en">commission</span>(<span class="pl-c1">Function</span> function,
      {<span class="pl-c1">List</span> positionalArgs<span class="pl-k">:</span> <span class="pl-k">const</span> [], <span class="pl-c1">Map</span> namedArgs<span class="pl-k">:</span> <span class="pl-k">const</span>{}}) <span class="pl-k">async</span> {
    <span class="pl-c1">BackgroundFunction</span> backgroundFunction <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-c1">BackgroundFunction</span>(function,
        positionalArguments<span class="pl-k">:</span> positionalArgs, namedArguments<span class="pl-k">:</span> namedArgs);

    <span class="pl-c1">_Job</span> job <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-c1">_Job</span>(<span class="pl-c1">this</span>, backgroundFunction);
    _jobs.<span class="pl-en">add</span>(job);
    <span class="pl-en">patrol</span>();

    <span class="pl-k">await</span> <span class="pl-k">for</span> (<span class="pl-c1">dynamic</span> finished <span class="pl-k">in</span> streamController.stream) {
      <span class="pl-k">if</span> (finished <span class="pl-k">==</span> job) {
        <span class="pl-k">return</span> job.result;
      }
    }
  }

  <span class="pl-c">/// Encourages idle <span class="pl-v">[Isolate]</span>s to take a <span class="pl-v">[_Job]</span> from</span>
<span class="pl-c">  /// the Queue and will spawn new a new <span class="pl-v">[Isolate]</span> if necessary</span>
<span class="pl-c">  ///</span>
<span class="pl-c">  /// This method is automatically called.</span>
<span class="pl-c">  /// I cannot easily image a reason why this should</span>
<span class="pl-c">  /// be called manually!</span>
<span class="pl-c"></span>  <span class="pl-en">patrol</span>() {
    _workers.<span class="pl-en">forEach</span>((worker) <span class="pl-k">=&gt;</span> worker.<span class="pl-en">incite</span>());
    <span class="pl-k">if</span> (_jobs.isNotEmpty) {
      <span class="pl-k">if</span> (_workers.length <span class="pl-k">&lt;</span> settings.workersMax) {
        <span class="pl-c1">this</span>._workers.<span class="pl-en">add</span>(
            <span class="pl-k">new</span> <span class="pl-c1">_Worker</span>(<span class="pl-c1">this</span>)
              ..<span class="pl-en">start</span>()
              ..<span class="pl-en">incite</span>());
        <span class="pl-en">print</span>(<span class="pl-s">"Site: Spawning worker. Total <span class="pl-s">${<span class="pl-v">_workers</span>.<span class="pl-v">length</span>}</span>"</span>);
      }
    }
  }


  <span class="pl-k">void</span> <span class="pl-en">_reportDeathOf</span>(<span class="pl-c1">_Worker</span> worker) {
    <span class="pl-c1">this</span>._workers.<span class="pl-en">remove</span>(worker);
    <span class="pl-en">print</span>(<span class="pl-s">"Site: Worker $<span class="pl-v">worker</span> died. Left: <span class="pl-s">${<span class="pl-v">_workers</span>.<span class="pl-v">length</span>}</span>"</span>);
  }


  <span class="pl-c">/// Will shut down this <span class="pl-v">[Site]</span> and kill all</span>
<span class="pl-c">  /// open resources/<span class="pl-v">[Isolate]</span>s</span>
<span class="pl-c">  ///</span>
<span class="pl-c">  /// You should not use this Site ever again after</span>
<span class="pl-c">  /// calling this method.</span>
<span class="pl-c">  ///</span>
<span class="pl-c">  /// Also make sure to call this method after</span>
<span class="pl-c">  /// the <span class="pl-v">[Site]</span> is not needed anymore.</span>
<span class="pl-c"></span>  <span class="pl-k">void</span> <span class="pl-en">close</span>() {
    <span class="pl-c1">this</span>.streamController<span class="pl-k">?</span>.<span class="pl-en">close</span>();
    <span class="pl-c1">this</span>.streamController <span class="pl-k">=</span> <span class="pl-c1">null</span>;
    <span class="pl-c1">this</span>._workers.<span class="pl-en">forEach</span>((worker) <span class="pl-k">=&gt;</span> worker.<span class="pl-en">close</span>());
    <span class="pl-c1">this</span>._workers.<span class="pl-en">clear</span>();
  }

  <span class="pl-en">finalize</span>() {
    <span class="pl-c1">this</span>.<span class="pl-en">close</span>();
  }
}

<span class="pl-c">/// All preferences for a <span class="pl-v">[Site]</span></span>
<span class="pl-c"></span><span class="pl-k">class</span> <span class="pl-c1">SiteSetting</span> {

  <span class="pl-c">/// How many worker <span class="pl-v">[Isolates]</span> can be spawned at max?</span>
<span class="pl-c"></span>  <span class="pl-k">final</span> <span class="pl-c1">int</span> workersMax;

  <span class="pl-c">/// How long is an <span class="pl-v">[Isolate]</span> allowed to idle, before it is killed?</span>
<span class="pl-c"></span>  <span class="pl-k">final</span> <span class="pl-c1">Duration</span> workerTimeout;

  <span class="pl-c">/// Will allow a maximum of 2 background <span class="pl-v">[Isolate]</span>s while</span>
<span class="pl-c">  /// killing idle <span class="pl-v">[Isolate]</span>s after 30 seconds</span>
<span class="pl-c"></span>  <span class="pl-k">static</span> <span class="pl-k">const</span> <span class="pl-c1">SiteSetting</span> <span class="pl-c1">STANDARD</span> <span class="pl-k">=</span> <span class="pl-k">const</span> <span class="pl-c1">SiteSetting</span>(<span class="pl-c1">2</span>, <span class="pl-k">const</span> <span class="pl-c1">Duration</span>(seconds<span class="pl-k">:</span> <span class="pl-c1">30</span>));

  <span class="pl-c">/// Will allow a maximum of 16 background <span class="pl-v">[Isolate]</span>s while</span>
<span class="pl-c">  /// killing idle <span class="pl-v">[Isolate]</span>s after 5 minutes.</span>
<span class="pl-c">  ///</span>
<span class="pl-c">  /// This is only for heavy multitasking applications.</span>
<span class="pl-c">  /// Not quite sure if Dart is the right language here!</span>
<span class="pl-c"></span>  <span class="pl-k">static</span> <span class="pl-k">const</span> <span class="pl-c1">SiteSetting</span> <span class="pl-c1">HEAVY</span> <span class="pl-k">=</span> <span class="pl-k">const</span> <span class="pl-c1">SiteSetting</span>(<span class="pl-c1">16</span>, <span class="pl-k">const</span> <span class="pl-c1">Duration</span>(minutes<span class="pl-k">:</span> <span class="pl-c1">5</span>));

  <span class="pl-c">/// Will allow a maximum of 2 background <span class="pl-v">[Isolate]</span> while</span>
<span class="pl-c">  /// killing idle <span class="pl-v">[Isolate]</span>s after 1 second.</span>
<span class="pl-c"></span>  <span class="pl-k">static</span> <span class="pl-k">const</span> <span class="pl-c1">SiteSetting</span> <span class="pl-c1">LIGHT</span> <span class="pl-k">=</span> <span class="pl-k">const</span> <span class="pl-c1">SiteSetting</span>(<span class="pl-c1">2</span>, <span class="pl-k">const</span> <span class="pl-c1">Duration</span>(seconds<span class="pl-k">:</span> <span class="pl-c1">1</span>));


  <span class="pl-k">const</span> <span class="pl-c1">SiteSetting</span>(<span class="pl-c1">this</span>.workersMax, <span class="pl-c1">this</span>.workerTimeout);
}



<span class="pl-c">/// Manages the connection to a dedicated <span class="pl-v">[Isolate]</span>.</span>
<span class="pl-c">///</span>
<span class="pl-c">/// Manages its own <span class="pl-v">[Isolate]</span> and is able</span>
<span class="pl-c">/// to work on <span class="pl-v">[_Job]</span> objects.</span>
<span class="pl-c"></span><span class="pl-k">class</span> <span class="pl-c1">_Worker</span> {

  <span class="pl-c">/// The site this worker belongs to</span>
<span class="pl-c"></span>  <span class="pl-c1">Site</span> site;

  <span class="pl-c">/// The workers own <span class="pl-v">[Isolate]</span></span>
<span class="pl-c"></span>  <span class="pl-c1">Isolate</span> _isolate;

  <span class="pl-c">/// Will be used for receiving messages</span>
<span class="pl-c">  /// from <span class="pl-v">[_isolate]</span></span>
<span class="pl-c"></span>  <span class="pl-c1">ReceivePort</span> _receivePort;

  <span class="pl-c">/// Will be used to send messages to</span>
<span class="pl-c">  /// <span class="pl-v">[_isolate]</span></span>
<span class="pl-c">  ///</span>
<span class="pl-c">  /// This should be null-checked, since</span>
<span class="pl-c">  /// the port is received from the <span class="pl-v">[_isolate]</span></span>
<span class="pl-c">  /// once it is running</span>
<span class="pl-c"></span>  <span class="pl-c1">SendPort</span> _sendPort;

  <span class="pl-c">/// The current job, this Worker is working on,</span>
<span class="pl-c">  /// or null if the Worker is idle.</span>
<span class="pl-c"></span>  <span class="pl-c1">_Job</span> _currentJob;

  <span class="pl-c1">_Worker</span>(<span class="pl-c1">this</span>.site);

  <span class="pl-c">/// Tells whether an <span class="pl-v">[Isolate]</span> is currently attached.</span>
<span class="pl-c">  /// Does NOT tell whether its IDLE or not!</span>
<span class="pl-c"></span>  <span class="pl-c1">bool</span> <span class="pl-k">get</span> running {
    <span class="pl-k">return</span> _isolate <span class="pl-k">!=</span> <span class="pl-c1">null</span>;
  }

  <span class="pl-c">/// Will make this Worker start working on an available job</span>
<span class="pl-c">  /// if it is currently idle!</span>
<span class="pl-c"></span>  <span class="pl-k">void</span> <span class="pl-en">incite</span>() {
    <span class="pl-k">if</span> (_currentJob <span class="pl-k">==</span> <span class="pl-c1">null</span> <span class="pl-k">&amp;&amp;</span> site._jobs.isNotEmpty) {
      _currentJob <span class="pl-k">=</span> site._jobs.<span class="pl-en">removeFirst</span>();
      <span class="pl-en">print</span>(<span class="pl-s">"Worker: start workiing on $<span class="pl-v">_currentJob</span>"</span>);
      <span class="pl-en">_startWorking</span>();
    }
  }


  <span class="pl-c">/// Send the <span class="pl-v">[_Job]</span> object <span class="pl-v">[_currentJob]</span> to the Isolate,</span>
<span class="pl-c">  /// which will start working on it.</span>
<span class="pl-c"></span>  <span class="pl-k">void</span> <span class="pl-en">_startWorking</span>() {
    <span class="pl-k">assert</span>(_currentJob <span class="pl-k">!=</span> <span class="pl-c1">null</span>);
    <span class="pl-k">if</span>(_sendPort<span class="pl-k">!=</span><span class="pl-c1">null</span>){
      <span class="pl-en">print</span>(<span class="pl-s">"Worker: delegating to isolate"</span>);
      _sendPort.<span class="pl-en">send</span>(_currentJob.function);
      <span class="pl-en">print</span>(<span class="pl-s">"Worker: waiting for isolate to finish"</span>);
    }
 }

 <span class="pl-c">/// receives the result for the computation associated with</span>
<span class="pl-c">  /// <span class="pl-v">[_currentJob]</span> and will "finish" the associated future</span>
<span class="pl-c">  /// by assigning the result <span class="pl-v">[x]</span> to it.</span>
<span class="pl-c"></span>  <span class="pl-k">void</span> <span class="pl-en">_receive</span>(<span class="pl-c1">dynamic</span> x) {
    <span class="pl-k">assert</span> (_currentJob <span class="pl-k">!=</span> <span class="pl-c1">null</span>);
    _currentJob.result <span class="pl-k">=</span> x;
    _currentJob <span class="pl-k">=</span> <span class="pl-c1">null</span>;
    <span class="pl-en">incite</span>();
  }

  <span class="pl-c">/// Starting the Worker will</span>
<span class="pl-c">  /// spawn the <span class="pl-v">[_isolate]</span> and retrieve the <span class="pl-v">[_sendPort]</span>.</span>
<span class="pl-c">  ///</span>
<span class="pl-c">  /// This will also lead in a call to <span class="pl-v">[_startWorking]</span> if</span>
<span class="pl-c">  /// a job is currently assigned.</span>
<span class="pl-c"></span>  <span class="pl-c1">Future</span> <span class="pl-en">start</span>() <span class="pl-k">async</span> {
    <span class="pl-c1">ReceivePort</span> exitReceiver <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-c1">ReceivePort</span>();
    exitReceiver.first.<span class="pl-en">then</span>((x) {
      <span class="pl-c1">this</span>.<span class="pl-en">close</span>();
      site.<span class="pl-en">_reportDeathOf</span>(<span class="pl-c1">this</span>);
    });

    _receivePort <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-c1">ReceivePort</span>();

    <span class="pl-c1">_WorkDay</span> _workDay <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-c1">_WorkDay</span>(site.settings, _receivePort.sendPort);
    _isolate <span class="pl-k">=</span>
    <span class="pl-k">await</span> <span class="pl-c1">Isolate</span>.<span class="pl-en">spawn</span>(_entryPoint, _workDay, onExit<span class="pl-k">:</span> exitReceiver.sendPort);

    <span class="pl-c1">int</span> counter <span class="pl-k">=</span> <span class="pl-c1">0</span>;
    _receivePort.<span class="pl-en">listen</span>((x) {
      <span class="pl-k">if</span>(counter <span class="pl-k">==</span> <span class="pl-c1">0</span>){
        _sendPort <span class="pl-k">=</span> x;
        <span class="pl-k">if</span>(_currentJob<span class="pl-k">!=</span><span class="pl-c1">null</span>) <span class="pl-en">_startWorking</span>();
      }
      <span class="pl-k">else</span> <span class="pl-en">_receive</span>(x);
      counter <span class="pl-k">++</span>;
    });


  }


  <span class="pl-c">/// Will kill the <span class="pl-v">[Isolate]</span> and this Worker should</span>
<span class="pl-c">  /// never be used again!</span>
<span class="pl-c"></span>  <span class="pl-k">void</span> <span class="pl-en">close</span>() {
    _isolate<span class="pl-k">?</span>.<span class="pl-en">kill</span>();
    _isolate <span class="pl-k">=</span> <span class="pl-c1">null</span>;
    _receivePort<span class="pl-k">?</span>.<span class="pl-en">close</span>();
    _receivePort <span class="pl-k">=</span> <span class="pl-c1">null</span>;
    _sendPort <span class="pl-k">=</span> <span class="pl-c1">null</span>;
    _currentJob <span class="pl-k">=</span> <span class="pl-c1">null</span>;
  }


  <span class="pl-c">/// The entry point of <span class="pl-v">[_isolate]</span>.</span>
<span class="pl-c"></span>  <span class="pl-k">static</span> <span class="pl-k">void</span> <span class="pl-en">_entryPoint</span>(<span class="pl-c1">_WorkDay</span> workDay) {
    <span class="pl-c1">ReceivePort</span> receivePort <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-c1">ReceivePort</span>();
    <span class="pl-c1">Stream</span> receiveStream <span class="pl-k">=</span> receivePort.<span class="pl-en">timeout</span>(workDay.settings.workerTimeout,
        onTimeout<span class="pl-k">:</span> (<span class="pl-c1">EventSink</span> sink) {
          <span class="pl-en">print</span>(<span class="pl-s">"Worker: timed out..."</span>);
          receivePort.<span class="pl-en">close</span>();
        });

    receiveStream.<span class="pl-en">listen</span>((<span class="pl-c1">BackgroundFunction</span> backgroundFunction) {
      <span class="pl-en">print</span>(<span class="pl-s">"Worker: working"</span>);
      <span class="pl-k">var</span> result <span class="pl-k">=</span> <span class="pl-en">backgroundFunction</span>();
      workDay.sendPort.<span class="pl-en">send</span>(result);
      <span class="pl-en">print</span>(<span class="pl-s">"Worker: idle"</span>);
    });

    workDay.sendPort.<span class="pl-en">send</span>(receivePort.sendPort);
  }
}


<span class="pl-c">/// The initial object sent to a <span class="pl-v">[Isolate]</span> by a <span class="pl-v">[_Worker]</span></span>
<span class="pl-c"></span><span class="pl-k">class</span> <span class="pl-c1">_WorkDay</span> {
  <span class="pl-k">final</span> <span class="pl-c1">SiteSetting</span> settings;
  <span class="pl-k">final</span> <span class="pl-c1">SendPort</span> sendPort;

  <span class="pl-c1">_WorkDay</span>(<span class="pl-c1">this</span>.settings, <span class="pl-c1">this</span>.sendPort);
}



<span class="pl-k">class</span> <span class="pl-c1">_Job</span> {
  <span class="pl-k">final</span> <span class="pl-c1">Site</span> _site;
  <span class="pl-k">final</span> <span class="pl-c1">BackgroundFunction</span> function;
  <span class="pl-c1">bool</span> finished <span class="pl-k">=</span> <span class="pl-c1">false</span>;
  <span class="pl-c1">dynamic</span> _result;

  <span class="pl-k">set</span> <span class="pl-en">result</span>(<span class="pl-c1">dynamic</span> result) {
    <span class="pl-c1">this</span>._result <span class="pl-k">=</span> result;
    <span class="pl-c1">this</span>.finished <span class="pl-k">=</span> <span class="pl-c1">true</span>;
    <span class="pl-c1">this</span>._site.streamController.<span class="pl-en">add</span>(<span class="pl-c1">this</span>);
  }

  <span class="pl-c1">dynamic</span> <span class="pl-k">get</span> result {
    <span class="pl-k">return</span> _result;
  }

  <span class="pl-c1">_Job</span>(<span class="pl-c1">this</span>._site, <span class="pl-c1">this</span>.function);
}

<span class="pl-k">class</span> <span class="pl-c1">BackgroundFunction</span> {
  <span class="pl-k">final</span> <span class="pl-c1">Function</span> function;
  <span class="pl-k">final</span> <span class="pl-c1">List</span> positionalArguments;
  <span class="pl-k">final</span> <span class="pl-c1">Map</span> namedArguments;

  <span class="pl-c1">BackgroundFunction</span>(<span class="pl-c1">this</span>.function,
      {<span class="pl-c1">this</span>.positionalArguments<span class="pl-k">:</span> <span class="pl-k">const</span>[],
        <span class="pl-c1">this</span>.namedArguments<span class="pl-k">:</span> <span class="pl-k">const</span>{}});

  <span class="pl-c1">dynamic</span> <span class="pl-en">call</span>() {
    <span class="pl-k">return</span> <span class="pl-c1">Function</span>.<span class="pl-en">apply</span>(function, positionalArguments, namedArguments);
  }
}</pre></div>
<p dir="auto">Customers would like to execute dart code as background processes on both iOS and Android, for things like syncing down data when wifi is available but the app is not open, etc.</p>
<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/mpcomplete/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/mpcomplete">@mpcomplete</a> created a background process on Android to execute Dart code to update flutter.  But I'm not aware of a parallel on iOS.</p>
<p dir="auto">This issue tracks the development of APIs in plugins or otherwise. Engine support for these abstractions is tracked in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="180798789" data-permission-text="Title is private" data-url="https://github.com/flutter/flutter/issues/6192" data-hovercard-type="issue" data-hovercard-url="/flutter/flutter/issues/6192/hovercard" href="https://github.com/flutter/flutter/issues/6192">#6192</a>.</p>