flutterhiveflutter-dependenciesflutter-hive

Flutter, Hive, GetIt => Problem Registering Box


I am currently developing a simple CRUD App in Flutter using the clean architecture, GetIt, Hive and BloC.

It is my first time using Hive and GetIt, and I get following Error when I run my app:

Bad state: GetIt: Object/factory with type Box is not registered inside GetIt. (Did you accidentally do GetIt sl=GetIt.instance(); instead of GetIt sl=GetIt.instance; Did you forget to register it?)

To make the mistake hunt simpler, I coded the important part of the app again, with the "Habit.dart" only containing a name, and the only feature I implemented is "GetAllHabits". The feature itself is not so important, the only important part is the GetIt and Hive-Part.

The simplified project: https://github.com/gag0s/clean_architecture_issue

Also I noticed that the generated file habit_model.g.dart was produced with an error, as it forgot the name argument in line 19.

For those who do not want to click through the project, here are the important bits:

data/models/habit_model.dart:

part 'habit_model.g.dart';

@HiveType(typeId: 0)
class HabitModel extends Habit {
  @HiveField(0)
  final String name;

  HabitModel({required this.name}) : super(name: name);

  Habit toEntity() => Habit(name: name);
}

data/datasources/habit_local_data_source.dart:

abstract interface class HabitLocalDataSource {
  List<HabitModel> getHabits();
}

class HabitLocalDataSourceImpl implements HabitLocalDataSource {
  final Box<HabitModel> box;
  HabitLocalDataSourceImpl(this.box);

  @override
  List<HabitModel> getHabits() {
    return box.values.toList();
  }
}

init_dependencies.dart:

final sl = GetIt.instance;

Future<void> initDependencies() async {
  _initHabit();

  Hive.init((await getApplicationDocumentsDirectory()).path);
  Hive.registerAdapter(HabitModelAdapter());
  sl.registerLazySingleton(() => Hive.openBox<HabitModel>("habits"));
}

void _initHabit() {
  sl
    ..registerFactory<HabitLocalDataSource>(() => HabitLocalDataSourceImpl(sl()))
    ..registerFactory<HabitRepository>(() => HabitRepositoryImpl(sl()))
    ..registerFactory<GetAllHabits>(() => GetAllHabits(sl()))
    ..registerLazySingleton<HabitBloc>(() => HabitBloc(getAllHabits: sl()));
}

main method:

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await initDependencies();
  runApp(MultiBlocProvider(providers: [
    BlocProvider(create: (_) => sl<HabitBloc>()),
  ], child: const MyApp()));
}

Thanks in advance for any help!


Solution

  • First of all, thanks for detailed description and example code on GitHub!

    I was able to dive in your sample project and here is what I found:

    1. Regarding malformed habit_model.g.dart – I was able to overcome this running dart run build_runner build --delete-conflicting-outputs. It just regenerated this file and all is okay. Here is code, in case you need it: https://gist.github.com/Sameri11/76bbe94651461d01d3102acce86f1e86

    2. Regarding GetIt error – I believe that main problem is that Hive.openBox returns Future, but it is never awaited. If await added and then awaited result of Box<HabitModel> used in registerLazySingleton – errors are gone.

    Something like this:

    //Before
      sl.registerLazySingleton(() => Hive.openBox<HabitModel>("habits"));
    
    //After
      final habitsBox = await Hive.openBox<HabitModel>("habits");
      sl.registerLazySingleton(() => habitsBox);
    

    I provided PR to your repo with all changes in case you need it, here it is: https://github.com/gag0s/clean_architecture_issue/pull/1

    Hope it'll help!