Sheitak
Sheitak

Reputation: 91

Use ObjectBox / Instantiate store and box with Flutter 2.5 and Riverpod

I am using ObjectBox on Flutter 2.5 with Riverpod. The goal is to allow fast caching of a lot of data from an API.

If there is a difference between remote data and that in the box, then we update. The person who no longer has the internet still has good data.

Has anyone managed to instantiate and best use Objectbox in flutter clean architecture with riverpod ? I found several relevant questions about it here and here. but I can't seem to get anything satisfactory at the moment ...

If you have any suggestions for doing this. I took into account the update that Objectbox made on their example of store creation.

The errors are always the same, either the _box or store is not instantiated or else, get null. I would update my post as I research.

[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: LateInitializationError: Field '_box@59089156' has not been initialized.

[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: LateInitializationError: Field 'store' has not been initialized.

------EDIT 21 oct.2021-----

Ok, thanks to the help and comments from my colleagues. I update my code to match. No more store or box instantiation problems.

My code

abstract class LocalDataSourceRepository<T> {
  Future<Coin?> getCoinById(dynamic id);
  Future<void> addCoin(T object);
}

The remote / local management is in this implementation, with getRemoteDataCoin which retrieves a full currency from the API and transforms it into an entity

class CoinRepositoryImpl extends LocalDataSourceRepository {

  final CoinRemoteApi _remoteApi;
  final ObjectBoxDatabase _objectBoxDatabase;

  CoinRepositoryImpl(
      this._remoteApi,
      this._objectBoxDatabase,
  );

  @override
  Future<Coin?> getCoinById(id) async {
    final _box = _objectBoxDatabase.store.box<Coin>();
    final Query<Coin> query = (_boxCoin.query(Coin_.coinId.equals(id))).build();

    if (query.findUnique() == null) {
      final coin = await getRemoteDataCoin(id);
      addCoin(coin);
      return query.findUnique();
    } else {
      return query.findUnique();
    }
  }

  @override
  Future<void> addCoin(object) async {
    final _box = _objectBoxDatabase.store.box<Coin>();
    _box.put(object);
  }

  Future<Coin> getRemoteDataCoin(selectedCoin) async {
    return _remoteApi.getCoinById(
        selectedCoin,
        const CoinRequest(
            localization: 'false',
            tickers: false,
            marketData: false,
            communityData: true,
            developerData: false,
            sparkline: false
        )
    ).then(
          (value) => value.toEntity(),
    );
  }
}
class ObjectBoxDatabase {
  late final Store store;
  late final Box<Coin> _box;

  ObjectBoxDatabase._create(this.store) {
     _box = Box<Coin>(store);
  }

  static Future<ObjectBoxDatabase> create() async {
    final store = await openStore();
    return ObjectBoxDatabase._create(store);
  }
}

My Riverpod providers.

final localCoinDatabaseProvider = Provider<ObjectBoxDatabase>((ref) => throw UnimplementedError());
final remoteCoinApiProvider = Provider<CoinRemoteApi>((ref) => CoinRemoteApi());

final coinRepositoryProvider = Provider<LocalDataSourceRepository>((ref) => CoinRepositoryImpl(
    ref.read(remoteCoinApiProvider),
    ref.read(localCoinDatabaseProvider)
));
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final objectBox = await ObjectBoxDatabase.create();
  runApp(
      ProviderScope(
          overrides: [
            localCoinDatabaseProvider.overrideWithValue(objectBox)
          ],
          child: const MyApp()
      )
  );
}

Upvotes: 3

Views: 1688

Answers (1)

MD Ismail Alam Khan
MD Ismail Alam Khan

Reputation: 160

Since you get the ObjectBoxDatabase using the .create method which is a future, you can either use a FutureProvider or overrides

FutureProvider:

final localCoinDatabaseProvider = FutureProvider<ObjectBoxDatabase>((ref) => ObjectBoxDatabase.create());

https://pub.dev/documentation/riverpod/latest/riverpod/FutureProvider-class.html

overrides:

final localCoinDatabaseProvider = Provider<ObjectBoxDatabase>((ref) => throw UnimplementedError());


Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final objectBox = await ObjectBoxDatabase.create();
  runApp(
      const ProviderScope(
        overrides: [localCoinDatabaseProvider.overrideWithValue(objectBox)]
        child: MyApp()
      )
  );
}

Upvotes: 2

Related Questions