Skip to content

Commit 8481811

Browse files
Merge pull request #316 from objectbox/flutter-init-store-once
Examples: init store in main, access through provider class
2 parents 2f8e6a1 + 19c51de commit 8481811

File tree

7 files changed

+196
-115
lines changed

7 files changed

+196
-115
lines changed

objectbox/example/README.md

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,27 +59,48 @@ Creating a store
5959

6060
### Flutter apps
6161

62+
For example, open the `Store` in a small helper class like this:
63+
6264
```dart
6365
import 'objectbox.g.dart'; // created by `flutter pub run build_runner build`
6466
65-
class _MyHomePageState extends State<MyHomePage> {
66-
Store? _store;
67-
68-
@override
69-
void initState() {
70-
super.initState();
67+
class ObjectBox {
68+
/// The Store of this app.
69+
late final Store store;
70+
71+
ObjectBox._create(this.store) {
72+
// Add any additional setup code, e.g. build queries.
73+
}
7174
75+
/// Create an instance of ObjectBox to use throughout the app.
76+
static Future<ObjectBox> create() async {
7277
// Future<Store> openStore() {...} is defined in the generated objectbox.g.dart
73-
openStore().then((Store store) {
74-
_store = store;
75-
});
78+
final store = await openStore();
79+
return ObjectBox._create(store);
7680
}
7781
}
7882
```
7983

80-
See [Flutter: read & write files](https://flutter.dev/docs/cookbook/persistence/reading-writing-files) for more info.
81-
If you didn't specify this path to ObjectBox, it would try to use a default directory "objectbox" in the current working
82-
directory, but it doesn't have permissions to write there: `failed to create store: 10199 Dir does not exist: objectbox (30)`.
84+
The best time to create the ObjectBox class is when your app starts.
85+
We suggest to do it in your app's `main()` function:
86+
87+
```dart
88+
/// Provides access to the ObjectBox Store throughout the app.
89+
late ObjectBox objectbox;
90+
91+
Future<void> main() async {
92+
// This is required so ObjectBox can get the application directory
93+
// to store the database in.
94+
WidgetsFlutterBinding.ensureInitialized();
95+
96+
objectbox = await ObjectBox.create();
97+
98+
runApp(MyApp());
99+
}
100+
```
101+
102+
Then the `Store` remains open throughout the lifetime of the app.
103+
This is typically fine and recommended for most use cases.
83104

84105
### Dart CLI apps
85106

objectbox/example/flutter/objectbox_demo/lib/main.dart

Lines changed: 14 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,25 @@
11
import 'dart:async';
22

33
import 'package:flutter/material.dart';
4-
import 'package:intl/intl.dart';
5-
import 'package:objectbox/objectbox.dart';
64

7-
import 'objectbox.g.dart';
5+
import 'model.dart';
6+
import 'objectbox.dart';
87

98
// ignore_for_file: public_member_api_docs
109

11-
@Entity()
12-
class Note {
13-
int id;
10+
/// Provides access to the ObjectBox Store throughout the app.
11+
late ObjectBox objectbox;
1412

15-
String text;
16-
String? comment;
17-
DateTime date;
13+
Future<void> main() async {
14+
// This is required so ObjectBox can get the application directory
15+
// to store the database in.
16+
WidgetsFlutterBinding.ensureInitialized();
1817

19-
Note(this.text, {this.id = 0, this.comment, DateTime? date})
20-
: date = date ?? DateTime.now();
18+
objectbox = await ObjectBox.create();
2119

22-
String get dateFormat => DateFormat('dd.MM.yyyy hh:mm:ss').format(date);
20+
runApp(MyApp());
2321
}
2422

25-
void main() => runApp(const MyApp());
26-
2723
class MyApp extends StatelessWidget {
2824
const MyApp({Key? key}) : super(key: key);
2925

@@ -44,60 +40,35 @@ class MyHomePage extends StatefulWidget {
4440
_MyHomePageState createState() => _MyHomePageState();
4541
}
4642

47-
class ViewModel {
48-
final Store _store;
49-
final Box<Note> _box;
50-
late final Stream<Query<Note>> _queryStream;
51-
52-
ViewModel(this._store) : _box = Box<Note>(_store) {
53-
final qBuilder = _box.query()..order(Note_.date, flags: Order.descending);
54-
_queryStream = qBuilder.watch(triggerImmediately: true);
55-
}
56-
57-
void addNote(Note note) => _box.put(note);
58-
59-
void removeNote(Note note) => _box.remove(note.id);
60-
61-
void dispose() {
62-
_store.close();
63-
}
64-
}
65-
6643
class _MyHomePageState extends State<MyHomePage> {
6744
final _noteInputController = TextEditingController();
6845
final _listController = StreamController<List<Note>>(sync: true);
69-
late final ViewModel _vm;
7046

7147
void _addNote() {
7248
if (_noteInputController.text.isEmpty) return;
73-
_vm.addNote(Note(_noteInputController.text));
49+
objectbox.noteBox.put(Note(_noteInputController.text));
7450
_noteInputController.text = '';
7551
}
7652

7753
@override
7854
void initState() {
7955
super.initState();
8056

81-
openStore().then((Store store) {
82-
_vm = ViewModel(store);
83-
84-
setState(() {});
57+
setState(() {});
8558

86-
_listController.addStream(_vm._queryStream.map((q) => q.find()));
87-
});
59+
_listController.addStream(objectbox.queryStream.map((q) => q.find()));
8860
}
8961

9062
@override
9163
void dispose() {
9264
_noteInputController.dispose();
9365
_listController.close();
94-
_vm.dispose();
9566
super.dispose();
9667
}
9768

9869
GestureDetector Function(BuildContext, int) _itemBuilder(List<Note> notes) =>
9970
(BuildContext context, int index) => GestureDetector(
100-
onTap: () => _vm.removeNote(notes[index]),
71+
onTap: () => objectbox.noteBox.remove(notes[index].id),
10172
child: Row(
10273
children: <Widget>[
10374
Expanded(
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import 'package:intl/intl.dart';
2+
import 'package:objectbox/objectbox.dart';
3+
4+
import 'objectbox.g.dart';
5+
6+
// ignore_for_file: public_member_api_docs
7+
8+
@Entity()
9+
class Note {
10+
int id;
11+
12+
String text;
13+
String? comment;
14+
15+
/// Note: Stored in milliseconds without time zone info.
16+
DateTime date;
17+
18+
Note(this.text, {this.id = 0, this.comment, DateTime? date})
19+
: date = date ?? DateTime.now();
20+
21+
String get dateFormat => DateFormat('dd.MM.yyyy hh:mm:ss').format(date);
22+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import 'model.dart';
2+
import 'objectbox.g.dart'; // created by `flutter pub run build_runner build`
3+
4+
/// Provides access to the ObjectBox Store throughout the app.
5+
///
6+
/// Create this in the apps main function.
7+
class ObjectBox {
8+
/// The Store of this app.
9+
late final Store store;
10+
11+
/// A Box of notes.
12+
late final Box<Note> noteBox;
13+
14+
/// A stream of all notes ordered by date.
15+
late final Stream<Query<Note>> queryStream;
16+
17+
ObjectBox._create(this.store) {
18+
noteBox = Box<Note>(store);
19+
20+
final qBuilder = noteBox.query()
21+
..order(Note_.date, flags: Order.descending);
22+
queryStream = qBuilder.watch(triggerImmediately: true);
23+
24+
// Add some demo data if the box is empty.
25+
if (noteBox.isEmpty()) {
26+
_putDemoData();
27+
}
28+
}
29+
30+
/// Create an instance of ObjectBox to use throughout the app.
31+
static Future<ObjectBox> create() async {
32+
// Future<Store> openStore() {...} is defined in the generated objectbox.g.dart
33+
final store = await openStore();
34+
return ObjectBox._create(store);
35+
}
36+
37+
void _putDemoData() {
38+
final demoNotes = [
39+
Note('Quickly add a note by writing text and pressing Enter'),
40+
Note('Delete notes by tapping on one'),
41+
Note('Write a demo app for ObjectBox')
42+
];
43+
noteBox.putMany(demoNotes);
44+
}
45+
}

objectbox/example/flutter/objectbox_demo_sync/lib/main.dart

Lines changed: 14 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,25 @@
11
import 'dart:async';
2-
import 'dart:io';
32

43
import 'package:flutter/material.dart';
5-
import 'package:intl/intl.dart';
6-
import 'package:objectbox/objectbox.dart';
7-
import 'package:objectbox_sync_flutter_libs/objectbox_sync_flutter_libs.dart';
84

9-
import 'objectbox.g.dart';
5+
import 'model.dart';
6+
import 'objectbox.dart';
107

118
// ignore_for_file: public_member_api_docs
129

13-
@Entity()
14-
@Sync()
15-
class Note {
16-
int id;
10+
/// Provides access to the ObjectBox Store throughout the app.
11+
late ObjectBox objectbox;
1712

18-
String text;
19-
String? comment;
20-
DateTime date;
13+
Future<void> main() async {
14+
// This is required so ObjectBox can get the application directory
15+
// to store the database in.
16+
WidgetsFlutterBinding.ensureInitialized();
2117

22-
Note(this.text, {this.id = 0, this.comment, DateTime? date})
23-
: date = date ?? DateTime.now();
18+
objectbox = await ObjectBox.create();
2419

25-
String get dateFormat => DateFormat('dd.MM.yyyy hh:mm:ss').format(date);
20+
runApp(MyApp());
2621
}
2722

28-
void main() => runApp(const MyApp());
29-
3023
class MyApp extends StatelessWidget {
3124
const MyApp({Key? key}) : super(key: key);
3225

@@ -47,74 +40,35 @@ class MyHomePage extends StatefulWidget {
4740
_MyHomePageState createState() => _MyHomePageState();
4841
}
4942

50-
class ViewModel {
51-
final Store _store;
52-
late final Box<Note> _box;
53-
late final Stream<Query<Note>> _queryStream;
54-
55-
ViewModel(Directory dir)
56-
: _store = Store(getObjectBoxModel(),
57-
directory: dir.path + '-sync',
58-
macosApplicationGroup: 'objectbox.demo' // replace with a real name
59-
) {
60-
_box = Box<Note>(_store);
61-
final qBuilder = _box.query()..order(Note_.date, flags: Order.descending);
62-
_queryStream = qBuilder.watch(triggerImmediately: true);
63-
64-
// TODO configure actual sync server address and authentication
65-
// For configuration and docs, see objectbox/lib/src/sync.dart
66-
// 10.0.2.2 is your host PC if an app is run in an Android emulator.
67-
// 127.0.0.1 is your host PC if an app is run in an iOS simulator.
68-
final syncServerIp = Platform.isAndroid ? '10.0.2.2' : '127.0.0.1';
69-
final syncClient =
70-
Sync.client(_store, 'ws://$syncServerIp:9999', SyncCredentials.none());
71-
syncClient.start();
72-
}
73-
74-
void addNote(Note note) => _box.put(note);
75-
76-
void removeNote(Note note) => _box.remove(note.id);
77-
78-
void dispose() {
79-
_store.close();
80-
}
81-
}
82-
8343
class _MyHomePageState extends State<MyHomePage> {
8444
final _noteInputController = TextEditingController();
8545
final _listController = StreamController<List<Note>>(sync: true);
86-
late final ViewModel _vm;
8746

8847
void _addNote() {
8948
if (_noteInputController.text.isEmpty) return;
90-
_vm.addNote(Note(_noteInputController.text));
49+
objectbox.noteBox.put(Note(_noteInputController.text));
9150
_noteInputController.text = '';
9251
}
9352

9453
@override
9554
void initState() {
9655
super.initState();
9756

98-
defaultStoreDirectory().then((dir) {
99-
_vm = ViewModel(dir);
100-
101-
setState(() {});
57+
setState(() {});
10258

103-
_listController.addStream(_vm._queryStream.map((q) => q.find()));
104-
});
59+
_listController.addStream(objectbox.queryStream.map((q) => q.find()));
10560
}
10661

10762
@override
10863
void dispose() {
10964
_noteInputController.dispose();
11065
_listController.close();
111-
_vm.dispose();
11266
super.dispose();
11367
}
11468

11569
GestureDetector Function(BuildContext, int) _itemBuilder(List<Note> notes) =>
11670
(BuildContext context, int index) => GestureDetector(
117-
onTap: () => _vm.removeNote(notes[index]),
71+
onTap: () => objectbox.noteBox.remove(notes[index].id),
11872
child: Row(
11973
children: <Widget>[
12074
Expanded(
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import 'package:intl/intl.dart';
2+
import 'package:objectbox/objectbox.dart';
3+
4+
import 'objectbox.g.dart';
5+
6+
// ignore_for_file: public_member_api_docs
7+
8+
@Entity()
9+
@Sync()
10+
class Note {
11+
int id;
12+
13+
String text;
14+
String? comment;
15+
16+
/// Note: Stored in milliseconds without time zone info.
17+
DateTime date;
18+
19+
Note(this.text, {this.id = 0, this.comment, DateTime? date})
20+
: date = date ?? DateTime.now();
21+
22+
String get dateFormat => DateFormat('dd.MM.yyyy hh:mm:ss').format(date);
23+
}

0 commit comments

Comments
 (0)