Reputation: 2678
all the examples, I have seen, initialize ObjectBox in a State(less/full)Widget. I am using a layered architecture (currently refactoring to DDD) and wonder, how to inject my ObjectBox properly.
In my repository, I inject the data sources using the injectable and the getit packages with
@injectable
@LazySingleton (as: IJournalsRepository)
class JournalsRepository implements IJournalsRepository {
final JournalsRemoteDataSource journalsRemoteDataSource;
final JournalsLocalDataSource journalsLocalDataSource;
JournalsRepository(this.journalsLocalDataSource, this.journalsRemoteDataSource);
Those packages then create an instance of JournalsRemoteDataSource
and of JournalsRemoteDataSource
and inject it into the repository.
The ObjectBox example shows for initialization
class _MyHomePageState extends State<MyHomePage> {
Store? _store;
@override
void initState() {
super.initState();
openStore().then((Store store) => _store = store;);
}
@override
void dispose() {
_store?.close(); // don't forget to close the store
super.dispose();
}
}
So I am lacking an idea on how an injector could initialize ObjectBox or how I could access the objectBox
object from within the injected JournalsRemoteDataSource
if I would initialize objectBox
in MyApp()
(which is upstream to the HomePage
)
PS: reopening the box in JournalsRemoteDataSource
on every read/write event has a very poor performance
========== UPDATE ========== supplementing my comment to @vaind
I have found your answer on this similar question in the meantime (not sure why I did not see it, initially). I hope to get this approach working here, too. However, I have still issues initializing the store. My prototype comes from Firestore and looks like this:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:injectable/injectable.dart';
@module
abstract class FirebaseInjectableModule {
@lazySingleton
FirebaseAuth get firebaseAuth => FirebaseAuth.instance;
}
though I do not understand where the getter firebaseAuth
comes from and haven't found any explanation, yet. Anyways, I adapted that to
import 'package:injectable/injectable.dart';
import 'package:objectbox/objectbox.dart';
import 'package:test/objectbox.g.dart';
@module
abstract class ObjectboxInjectableModule {
@lazySingleton
Future<Store> get store async => await openStore();
}
and use this with
@LazySingleton (as: ILocalDataSource)
class ObjectBoxDataSource implements ILocalDataSource {
final Store _store;
final Box<JournalOboxEntity> _box;
ObjectBoxDataSource(this._store) : _box = _store.box();
Besides final Store _store
being grey in IntelliJ (unused variable), I receive the error
You tried to access an instance of Store that is not ready yet
'package:get_it/get_it_impl.dart':
Failed assertion: line 404 pos 9: 'instanceFactory.isReady'
Upvotes: 2
Views: 1947
Reputation: 2678
So following another answer of vaind, I implemented this as follows. My architecture follows a merge of Reso Coder's DDD and Clean Architecture tutorials. Basically it is DDD with the local/remote data source layer of Clean Architecture.
INFRASTRUCTURE directory
abstract data sources
abstract class ILocalDataSource {
Future<JournalDto> getJournal(int id);
Future<void> storeJournal(JournalDto record);
}
abstract class IRemoteDataSource {
Future<JournalDto> getJournal(int problemClassId);
}
data source implementation
@LazySingleton (as: ILocalDataSource)
class ObjectBoxDataSource implements ILocalDataSource {
final Store _store;
final Box<JournalOboxEntity> _box;
ObjectBoxDataSource(this._store) : _box = _store.box();
injectable module in infrastructure/core
@module
abstract class ObjectBoxInjectableModule {
@preResolve // <<<<<<<<<<<<< needed for async init
@lazySingleton
Future<Store> get store async => await openStore();
}
And now the trick to get it work: My later errors where caused by an injector init not yet finished. After changing injection.dart
in the root folder to a Future
and await
ing the call in main()
, it worked. injection.dart
now looks like this:
final GetIt getIt = GetIt.instance;
@injectableInit
Future<void> configureInjection(String env) async {
$initGetIt(getIt, environment: env);
}
Upvotes: 1
Reputation: 2386
I don't have experience with packages get_it
& injectable
, but from the docs, I think the following alternatives would work. Using get_it
directly, not sure about the right way to achieve the same with injectable
(generator for get_it
) but I guess if you're familiar with it you can configure it to generate the same code.
GetIt.I.registerSingletonAsync<Store>(openStore);
main()
, probably preferrablechange your main
to sth like:
void main() async {
GetIt.I.registerSingleton<Store>(await openStore());
runApp(MyApp());
}
Note: Looks like get_it
provides a way to reset, which would result in reopening the same store. To avoid issues if you use that, you'd also need to implement a version of get_it
's dispose
that calls store.close()
.
Upvotes: 0