mirror of
https://github.com/johrpan/musicus_mobile.git
synced 2025-10-26 10:47:25 +01:00
Run Moor within a background isolate
This basically follows the guidelines at https://moor.simonbinder.eu/docs/advanced-features/isolates/. In the future we will be able to have multiple simultaneous database connections.
This commit is contained in:
parent
00def5382e
commit
e0fc60f9eb
3 changed files with 72 additions and 12 deletions
6
build.yaml
Normal file
6
build.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
targets:
|
||||||
|
$default:
|
||||||
|
builders:
|
||||||
|
moor_generator:
|
||||||
|
options:
|
||||||
|
generate_connect_constructor: true
|
||||||
|
|
@ -1,10 +1,63 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:isolate';
|
||||||
|
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:moor/isolate.dart';
|
||||||
|
import 'package:moor/moor.dart';
|
||||||
|
import 'package:moor_ffi/moor_ffi.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'package:path_provider/path_provider.dart' as pp;
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import 'database.dart';
|
import 'database.dart';
|
||||||
|
|
||||||
|
// The following code was taken from
|
||||||
|
// https://moor.simonbinder.eu/docs/advanced-features/isolates/ and just
|
||||||
|
// slightly modified.
|
||||||
|
|
||||||
|
Future<MoorIsolate> _createMoorIsolate() async {
|
||||||
|
// This method is called from the main isolate. Since we can't use
|
||||||
|
// getApplicationDocumentsDirectory on a background isolate, we calculate
|
||||||
|
// the database path in the foreground isolate and then inform the
|
||||||
|
// background isolate about the path.
|
||||||
|
final dir = await pp.getApplicationDocumentsDirectory();
|
||||||
|
final path = p.join(dir.path, 'db.sqlite');
|
||||||
|
final receivePort = ReceivePort();
|
||||||
|
|
||||||
|
await Isolate.spawn(
|
||||||
|
_startBackground,
|
||||||
|
_IsolateStartRequest(receivePort.sendPort, path),
|
||||||
|
);
|
||||||
|
|
||||||
|
// _startBackground will send the MoorIsolate to this ReceivePort.
|
||||||
|
return (await receivePort.first as MoorIsolate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startBackground(_IsolateStartRequest request) {
|
||||||
|
// This is the entrypoint from the background isolate! Let's create
|
||||||
|
// the database from the path we received.
|
||||||
|
final executor = VmDatabase(File(request.targetPath));
|
||||||
|
// We're using MoorIsolate.inCurrent here as this method already runs on a
|
||||||
|
// background isolate. If we used MoorIsolate.spawn, a third isolate would be
|
||||||
|
// started which is not what we want!
|
||||||
|
final moorIsolate = MoorIsolate.inCurrent(
|
||||||
|
() => DatabaseConnection.fromExecutor(executor),
|
||||||
|
);
|
||||||
|
// Inform the starting isolate about this, so that it can call .connect().
|
||||||
|
request.sendMoorIsolate.send(moorIsolate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to bundle the SendPort and the target path, since isolate entrypoint
|
||||||
|
// functions can only take one parameter.
|
||||||
|
class _IsolateStartRequest {
|
||||||
|
final SendPort sendMoorIsolate;
|
||||||
|
final String targetPath;
|
||||||
|
|
||||||
|
_IsolateStartRequest(this.sendMoorIsolate, this.targetPath);
|
||||||
|
}
|
||||||
|
|
||||||
enum BackendStatus {
|
enum BackendStatus {
|
||||||
loading,
|
loading,
|
||||||
setup,
|
setup,
|
||||||
|
|
@ -36,6 +89,7 @@ class BackendState extends State<Backend> {
|
||||||
Database db;
|
Database db;
|
||||||
String musicLibraryUri;
|
String musicLibraryUri;
|
||||||
|
|
||||||
|
MoorIsolate _moorIsolate;
|
||||||
SharedPreferences _shPref;
|
SharedPreferences _shPref;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -53,7 +107,10 @@ class BackendState extends State<Backend> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _load() async {
|
Future<void> _load() async {
|
||||||
db = Database('musicus.sqlite');
|
_moorIsolate = await _createMoorIsolate();
|
||||||
|
final dbConnection = await _moorIsolate.connect();
|
||||||
|
db = Database.connect(dbConnection);
|
||||||
|
|
||||||
_shPref = await SharedPreferences.getInstance();
|
_shPref = await SharedPreferences.getInstance();
|
||||||
musicLibraryUri = _shPref.getString('musicLibraryUri');
|
musicLibraryUri = _shPref.getString('musicLibraryUri');
|
||||||
|
|
||||||
|
|
@ -110,6 +167,12 @@ class BackendState extends State<Backend> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
_moorIsolate.shutdownAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _InheritedBackend extends InheritedWidget {
|
class _InheritedBackend extends InheritedWidget {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,6 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:moor/moor.dart';
|
import 'package:moor/moor.dart';
|
||||||
import 'package:moor_ffi/moor_ffi.dart';
|
|
||||||
import 'package:path/path.dart' as p;
|
|
||||||
import 'package:path_provider/path_provider.dart' as pp;
|
|
||||||
|
|
||||||
part 'database.g.dart';
|
part 'database.g.dart';
|
||||||
|
|
||||||
|
|
@ -38,13 +34,8 @@ class PerformanceModel {
|
||||||
'database.moor',
|
'database.moor',
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
class Database extends _$Database {
|
class Database extends _$Database {
|
||||||
Database(String fileName)
|
Database.connect(DatabaseConnection connection) : super.connect(connection);
|
||||||
: super(LazyDatabase(() async {
|
|
||||||
final dir = await pp.getApplicationDocumentsDirectory();
|
|
||||||
final file = File(p.join(dir.path, fileName));
|
|
||||||
return VmDatabase(file);
|
|
||||||
}));
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 1;
|
int get schemaVersion => 1;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue