Problem during adding elements in Flutter Hive

I'm facing some problems when using Hive in Flutter for the first time. Before that, I was using Sqflite, and things just performed as expected, but I switched to Hive to look more performant I switch to Hive. The problem is that when I initialize two Hive boxes "AvatarsPack" and "AvatarItem" with data, even awaiting for each insertion on DB, it looks like Hive returns before all insertions been done, so my FutureBuilder builds without getting the values. I'm trying to solve this problem for about 3 days and I almost switching back to Sqflite, but I remember that there are amazing guys right here that would solve this issue in seconds, so it's what I'm doing, I'm asking all you for help. Thank you by reading until here, below it's the code:

avatars_view.dart

  final _controller = AvatarsController();

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: _controller.initializeRepository(),
        builder: (context, snapshot) {
          Future.delayed(Duration(seconds: 1)).then((value) => print(_controller.getAvatarsPacks()[9].avatars));

          if (snapshot.connectionState == ConnectionState.done) {
            print('@@@@@${_controller.getAvatarsPacks()[0].avatars}');
            return MyShop(
              getOwnedItems: _controller.getOwnedAvatars,
              ownedTabTile: 'Owned',
              isScrollable: true,
              headers: _controller.getHeaders(),
              bodies:
                  _controller.getAvatarsPacks().map((e) => e.avatars).toList(),
            );
          }

          return Container();
        });
  }
}

avatars_controller.dart

  final _repository = AvatarsRepository();

  final Map<String, int> _AVATARS_PACKS_AMOUNT = {
    'superheroes': 50,
    'children': 30,
    'halloween-1': 50,
    'halloween-2': 50,
    'halloween-3': 50,
    'hospital': 18,
    'people-1': 50,
    'people-2': 50,
    'people-3': 18,
    'professions': 50,
  };

  List<AvatarsPack> getAvatarsPacks() {
    return _repository.getAllAvatarsPacks();
  }

  Future<void> initializeRepository() async {
    await _repository
        .openBoxes()
        .then((value) => print('----Boxes are oppened'));
    await _clearBoxes().then((value) => print('----Boxes were cleared'));
    if (_repository.isEmpty()) {
      print('----boxes are empty');
      await _initializeRepositoryData().then((value) =>
          print('avatars quantity: ${_repository.getQuantityAvatarItems()}'));
    }

    return;
  }

  List<String> getHeaders() {
    return _AVATARS_PACKS_AMOUNT.keys.toList();
  }

  List<AvatarItem> getOwnedAvatars() {
    return _repository.getOwnedAvatars();
  }

  void updateAvatarItem(AvatarItem avatarItem) =>
      _repository.updateAvatarItem(avatarItem);

  Future<void> _initializeRepositoryData() async {
    print('*******_initializeRepositoryData called()');
    return _AVATARS_PACKS_AMOUNT.forEach((key, quantity) async {
      final avatarsPack = AvatarsPack.create(
          packID: key,
          quantity: quantity,
          packItemPrice: Money.all(coins: 50, diamonds: 5));
      await _repository.addPack(avatarsPack);
    });
  }

  Future<void> _clearBoxes() {
    return _repository.clearBoxes();
  }

  @override
  FutureOr onClose() {
    _repository.closeBoxes();
    super.onClose();
  }
}

avatars_repository.dart

  Box _avatarsPackBox;
  Box _avatarItemBox;

  final AVATAR_PACK = 'avatarsPack';
  final AVATAR_ITEM = 'avatarItem';

  Box get _avatarsPackInstance {
    return _avatarsPackBox ??= Hive.box(AVATAR_PACK);
  }

  Box get _avatarItemInstance {
    return _avatarItemBox ??= Hive.box(AVATAR_ITEM);
  }

  Future<void> addPack(AvatarsPack avatarsPack) async {
    await _avatarsPackInstance.add(avatarsPack.toJson());

    return avatarsPack.avatars.forEach((element) async {
      await _avatarItemInstance.add(element.toJson());
    });
  }

  List<AvatarsPack> getAllAvatarsPacks() {
    final avatarsPacks = _avatarsPackInstance.values
        .map((json) => AvatarsPack.fromJson(json))
        .toList();

    avatarsPacks.forEach((avatarPack) {
      avatarPack.avatars = getAvatarItemsFromPack(avatarPack.packID);
    });

    return avatarsPacks;
  }

  Future<void> addAvatarItem(AvatarItem avatarItem) async {
    await _avatarItemInstance.add(avatarItem.toJson());
    return;
  }

  Future<void> updateAvatarItem(AvatarItem avatarItem) {
    final index =
        getAllAvatarItems().indexWhere((e) => e.pack == avatarItem.pack);
    return _avatarItemInstance.putAt(index, avatarItem.toJson());
  }

  List<AvatarItem> getAllAvatarItems() {
    return _avatarItemInstance.values
        .map((json) => AvatarItem.fromJson(json))
        .toList();
  }

  int getQuantityAvatarItems() {
    return _avatarItemInstance.values.length;
  }

  List<AvatarItem> getAvatarItemsFromPack(String packID) {
    final List<AvatarItem> avatars = [];
    getAllAvatarItems().forEach((avatarItem) {
      if (avatarItem.pack == packID) avatars.add(avatarItem);
    });
    return avatars;
  }

  List<AvatarItem> getOwnedAvatars() {
    return getAllAvatarItems().where((element) =>
        element.isOwned()).toList();
  }

  Future<void> openBoxes() async {
    await Hive.openBox(AVATAR_PACK);
    await Hive.openBox(AVATAR_ITEM);
    return;
  }

  Future<void> closeBoxes() async {
    await _avatarsPackInstance.close();
    await _avatarItemInstance.close();
    return;
  }

  Future<void> clearBoxes() async {
    await _avatarsPackInstance.clear();
    await _avatarItemInstance.clear();
    return;
  }

  bool isEmpty() {
    return _avatarsPackInstance.isEmpty;
  }
}

Concerning my avatars images, they are in folders which names are the same as their packID and each folder contains X elements named in this way img-0, img-2, ..., img-[x-1], img-x . Any feedback will be appreciated, thanks :)

Upvotes: 0

Views: 1022

Answers (1)

derZorn
derZorn

Reputation: 254

Try using a ValueListenableBuilder() instead of the FutureBuilder(). This watches changes on the Box and reflects those accordingly.

import 'package:hive_flutter/hive_flutter.dart';


ValueListenableBuilder(
          valueListenable:
              Hive.box(YOURBOX).listenable(),
          builder: (context, Box box, _) {
            return SomeWidget(withSomeData);
          },

Upvotes: 1

Related Questions