Moor: Isolates in iOS

Created on 3 Mar 2020  Â·  2Comments  Â·  Source: simolus3/moor

I would like to use the database in the background thread.
I implemented it using the Isolates doc. It works good on Android but in iOS I receive the following error:

Unsupported operation: Isolate.resolvePackageUri ... 
#0      Isolate.resolvePackageUri (dart:isolate-patch/isolate_patch.dart:350:7)
#1      Isolate.spawn (dart:isolate-patch/isolate_patch.dart:388:32)
#2      MoorIsolate.spawn (package:moor/src/runtime/isolate/moor_isolate.dart:75:19)
#3      workManagerCallbackDispatcher.<anonymous closure> (package:ubitime/main_isolated.dart:59:41)
#4      _asyncThenWrapperHelper.<anonymous closure> (dart:async-patch/async_patch.dart:73:64)
#5      _rootRunUnary (dart:async/zone.dart:1134:38)
#6      _CustomZone.runUnary (dart:async/zone.dart:1031:19)
#7      _FutureListener.handleValue (dart:async/future_impl.dart:139:18)
#8      Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:680:45)
#9      Future._propagateToListeners (dart:async/future_impl.dart:709:32)
#10     Future._completeWithValue (dart:async/future_impl.dart:524:5)
#11     _AsyncAwaitCompleter.complete (dart:async-patch/async_patch.dart:32:15)
#12     _completeOnAsyncReturn (dart:async-patch/async_patch.dart:290:13)
#13     initLog (package:ubitime/main.dart)
#14     _asyncThenWrapperHelper.<anonymous closure> (dart:async-patch/async_patch.dart:73:64)
#15     _rootRunUnary (dart:async/zone.dart:1134:38)
#16     _CustomZone.runUnary (dart:async/zone.dart:1031:19)
#17     _FutureListener.handleValue (dart:async/future_impl.dart:139:18)
#18     Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:680:45)
#19     Future._propagateToListeners (dart:async/future_impl.dart:709:32)
#20     Future._completeWithValue (dart:async/future_impl.dart:524:5)
#21     _AsyncAwaitCompleter.complete (dart:async-patch/async_patch.dart:32:15)
#22     _completeOnAsyncReturn (dart:async-patch/async_patch.dart:290:13)
#23     getApplicationSupportDirectory (package:path_provider/path_provider.dart)
#24     _asyncThenWrapperHelper.<anonymous closure> (dart:async-patch/async_patch.dart:73:64)
#25     _rootRunUnary (dart:async/zone.dart:1134:38)
#26     _CustomZone.runUnary (dart:async/zone.dart:1031:19)
#27     _FutureListener.handleValue (dart:async/future_impl.dart:139:18)
#28     Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:680:45)
#29     Future._propagateToListeners (dart:async/future_impl.dart:709:32)
#30     Future._completeWithValue (dart:async/future_impl.dart:524:5)
#31     _AsyncAwaitCompleter.complete (dart:async-patch/async_patch.dart:32:15)
#32     _completeOnAsyncReturn (dart:async-patch/async_patch.dart:290:13)
#33     MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart)
#34     _asyncThenWrapperHelper.<anonymous closure> (dart:async-patch/async_patch.dart:73:64)
#35     _rootRunUnary (dart:async/zone.dart:1134:38)
#36     _CustomZone.runUnary (dart:async/zone.dart:1031:19)
#37     _FutureListener.handleValue (dart:async/future_impl.dart:139:18)
#38     Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:680:45)
#39     Future._propagateToListeners (dart:async/future_impl.dart:709:32)
#40     Future._completeWithValue (dart:async/future_impl.dart:524:5)
#41     Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:554:7)
#42     _rootRun (dart:async/zone.dart:1126:13)
#43     _CustomZone.run (dart:async/zone.dart:1023:19)
#44     _CustomZone.runGuarded (dart:async/zone.dart:925:7)
#45     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:965:23)
#46     _microtaskLoop (dart:async/schedule_microtask.dart:43:21)
#47     _startMicrotaskLoop (dart:async/schedule_microtask.dart:52:5)

Maybe the problem is related to this issue and it has nothing to do with Moor but I would like to hear your opinion as well.

Please also note that I use WorkManager and I simulated the background fetch from Xcode.

flutter --version
Flutter 1.12.13+hotfix.8 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 0b8abb4724 (3 weeks ago) • 2020-02-11 11:44:36 -0800
Engine • revision e1e6ced81d
Tools • Dart 2.7.0
dependencies:
  moor: ^2.4.1
  moor_ffi: ^0.4.0

dev_dependencies:
  moor_generator: ^2.4.0

Did you see such problems on iOS side or did I miss something?

Thank you in advance.

Most helpful comment

Thank you for your reply.

It turned out that this has nothing to do with Moor. We are already in a background isolate when WorkManager's callbackDispatcher is called. Fortunately we have access also to getApplicationDocumentsDirectory so the database can be initialised like in the main isolate.

I will add some code. Maybe it will be useful for someone who wants to try Moor with WorkManager.

Moor initialisation like suggested on the Getting Started page.

@UseMoor(
    tables: [...],
    daos: [...])
class Database extends _$Database {

  Database() : super(_openConnection());

  @override
  int get schemaVersion => 1;
}

LazyDatabase _openConnection() {
  return LazyDatabase(() async {
    final dbFolder = await getApplicationDocumentsDirectory();
    final file = File(join(dbFolder.path, Const.databaseName));
    return VmDatabase(file);
  });
}

The callbackDispatcher of WorkManager.

void callbackDispatcher() {
  Workmanager.executeTask((task, inputData)  async {

    var database = Database();
    /// You can use the database here normally.

    bool success = true;
    return Future.value(success);
  });
}

Thank you again.

All 2 comments

There is nothing in moor that calls Isolate.resolvePackageUri, we just call Isolate.spawn. I would expect that to work in all cases, so I'm inclined to call this a Flutter bug.

If you use something like Flutter's compute function from the background, does that work? If it does, I can take a look at what moor might be doing differently. If it doesn't, it's definitely a Flutter bug...

Thank you for your reply.

It turned out that this has nothing to do with Moor. We are already in a background isolate when WorkManager's callbackDispatcher is called. Fortunately we have access also to getApplicationDocumentsDirectory so the database can be initialised like in the main isolate.

I will add some code. Maybe it will be useful for someone who wants to try Moor with WorkManager.

Moor initialisation like suggested on the Getting Started page.

@UseMoor(
    tables: [...],
    daos: [...])
class Database extends _$Database {

  Database() : super(_openConnection());

  @override
  int get schemaVersion => 1;
}

LazyDatabase _openConnection() {
  return LazyDatabase(() async {
    final dbFolder = await getApplicationDocumentsDirectory();
    final file = File(join(dbFolder.path, Const.databaseName));
    return VmDatabase(file);
  });
}

The callbackDispatcher of WorkManager.

void callbackDispatcher() {
  Workmanager.executeTask((task, inputData)  async {

    var database = Database();
    /// You can use the database here normally.

    bool success = true;
    return Future.value(success);
  });
}

Thank you again.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tony123S picture tony123S  Â·  4Comments

simolus3 picture simolus3  Â·  4Comments

Beloin picture Beloin  Â·  4Comments

VadimOsovsky picture VadimOsovsky  Â·  3Comments

easazade picture easazade  Â·  3Comments