Jaydip Pawar
Jaydip Pawar

Reputation: 135

How to solve the Box not Found error Hive Flutter

I have a homescreen in which I have created a 4 navigation screen, so when user enter login id and password then it calls the homescreen. But for the first time when user navigate to the homescreen it shows the Box is not initialized but when I click on Bottom navigation bar it shows the list but I want to show the list even user login first.

Here is my error:

enter image description here

Here is my HomeScreen code when user login:

import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
import 'package:secret_keeper/Database/Hive/BankModel.dart';
import 'package:secret_keeper/Database/Hive/CardModel.dart';
import 'package:secret_keeper/Database/Hive/NotesModel.dart';
import 'package:secret_keeper/Database/Hive/PasswordModel.dart';
import 'package:secret_keeper/screens/home_screen/banks/BanksNavigation.dart';
import 'package:secret_keeper/screens/home_screen/cards/CardsNavigation.dart';
import 'package:secret_keeper/screens/home_screen/notes/NotesNavigation.dart';
import 'package:secret_keeper/screens/home_screen/passwords/PasswordsNavigation.dart';
import 'package:secret_keeper/screens/input_screen/bank_input/BankInput.dart';
import 'package:secret_keeper/screens/input_screen/card_input/CardInput.dart';
import 'package:secret_keeper/screens/input_screen/note_input/NoteInput.dart';
import 'package:secret_keeper/screens/input_screen/password_input/PasswordInput.dart';

Box passwordBox, cardBox, bankBox, notesBox;

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  //Properties

  int currentTab = 0;
  final List<Widget> screens = [
    PasswordsNavigation(),
    CardsNavigation(),
    BanksNavigation(),
    NotesNavigation(),
  ];

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    Hive.registerAdapter(PasswordModelAdapter());
    Hive.registerAdapter(CardModelAdapter());
    Hive.registerAdapter(BankModelAdapter());
    Hive.registerAdapter(NotesModelAdapter());
    _openBox();
  }

  Future _openBox() async {
    WidgetsFlutterBinding.ensureInitialized();
    var dir = await getApplicationDocumentsDirectory();
    Hive.init(dir.path);
    passwordBox = await Hive.openBox<PasswordModel>('passwordBox');
    cardBox = await Hive.openBox<CardModel>('cardBox');
    bankBox = await Hive.openBox<BankModel>('bankBox');
    notesBox = await Hive.openBox<NotesModel>('notesBox');
    return;
  }

  //Active Page (Tab)

  Widget currentScreen = PasswordsNavigation();
  final PageStorageBucket bucket = PageStorageBucket();
  Icon cusIcon = Icon(Icons.search);
  Widget cusSearchBar = Row(children: [
    Text(
      "SECRET",
      style: TextStyle(color: Colors.orange[900], fontWeight: FontWeight.w700),
    ),
    Text(
      "KEEPER",
      style: TextStyle(color: Colors.black87, fontWeight: FontWeight.w700),
    ),
  ]);

  void checkNavigation(){
    if(currentTab == 0)
      Navigator.push(context, MaterialPageRoute(builder: (context) => PasswordInput()));
    else if(currentTab == 1)
      Navigator.push(context, MaterialPageRoute(builder: (context) => CardInput()));
    else if(currentTab == 2)
      Navigator.push(context, MaterialPageRoute(builder: (context) => BankInput()));
    else
      Navigator.push(context, MaterialPageRoute(builder: (context) => NoteInput()));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: cusSearchBar,
        actions: [
          IconButton(
            onPressed: () {
              setState(() {
                if (this.cusIcon.icon == Icons.search) {
                  this.cusIcon = Icon(Icons.cancel, color: Colors.black87);
                  this.cusSearchBar = Container(
                    height: 50,
                    child: TextField(
                      textInputAction: TextInputAction.go,
                      autofocus: true,
                      decoration: InputDecoration(
                          border: InputBorder.none, hintText: "Search here"),
                      style: TextStyle(
                        fontSize: 20.0,
                      ),
                    ),
                  );
                } else {
                  this.cusIcon = Icon(Icons.search);
                  this.cusSearchBar = Row(children: [
                    Text(
                      "SECRET",
                      style: TextStyle(
                          color: Colors.orange[900],
                          fontWeight: FontWeight.w700),
                    ),
                    Text(
                      "KEEPER",
                      style: TextStyle(
                          color: Colors.black87, fontWeight: FontWeight.w700),
                    ),
                  ]);
                }
              });
            },
            icon: cusIcon,
          ),
          IconButton(
            onPressed: () {},
            icon: Icon(Icons.more_vert),
          ),
        ],
      ),
      body: PageStorage(
        child: currentScreen,
        bucket: bucket,
      ),

      //FAB Button

      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        backgroundColor: Colors.orangeAccent,
        onPressed: () {
          checkNavigation();
        },
      ),

      //FAB Position

      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,

      //Bottom App Bar

      bottomNavigationBar: BottomAppBar(
        shape: CircularNotchedRectangle(),
        child: Container(
          height: 60,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Row(
                children: [
                  MaterialButton(
                    minWidth: 40,
                    onPressed: () {
                      setState(() {
                        currentScreen = PasswordsNavigation();
                        currentTab = 0;
                      });
                    },
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Icon(
                          Icons.paste_sharp,
                          color: currentTab == 0 ? Colors.orange : Colors.grey,
                        ),
                        Text(
                          'Passwords',
                          style: TextStyle(
                            color:
                                currentTab == 0 ? Colors.orange : Colors.grey,
                          ),
                        ),
                      ],
                    ),
                  ),
                  MaterialButton(
                    minWidth: 40,
                    onPressed: () {
                      setState(() {
                        currentScreen = CardsNavigation();
                        currentTab = 1;
                      });
                    },
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Icon(
                          Icons.credit_card_rounded,
                          color: currentTab == 1 ? Colors.orange : Colors.grey,
                        ),
                        Text(
                          'Cards',
                          style: TextStyle(
                            color:
                                currentTab == 1 ? Colors.orange : Colors.grey,
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
              Row(
                children: [
                  MaterialButton(
                    minWidth: 40,
                    onPressed: () {
                      setState(() {
                        currentScreen = BanksNavigation();
                        currentTab = 2;
                      });
                    },
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Icon(
                          Icons.food_bank_outlined,
                          color: currentTab == 2 ? Colors.orange : Colors.grey,
                        ),
                        Text(
                          'Banks',
                          style: TextStyle(
                            color:
                                currentTab == 2 ? Colors.orange : Colors.grey,
                          ),
                        ),
                      ],
                    ),
                  ),
                  MaterialButton(
                    minWidth: 40,
                    onPressed: () {
                      setState(() {
                        currentScreen = NotesNavigation();
                        currentTab = 3;
                      });
                    },
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Icon(
                          Icons.notes,
                          color: currentTab == 3 ? Colors.orange : Colors.grey,
                        ),
                        Text(
                          'Notes',
                          style: TextStyle(
                            color:
                                currentTab == 3 ? Colors.orange : Colors.grey,
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Here is my First Navigation Screen Code where i want to show the list:

import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:path_provider/path_provider.dart';
import 'package:secret_keeper/Database/Hive/PasswordModel.dart';
import 'package:secret_keeper/screens/home_screen/Home.dart';

class PasswordsNavigation extends StatefulWidget {
  @override
  _PasswordsNavigationState createState() => _PasswordsNavigationState();
}

class _PasswordsNavigationState extends State<PasswordsNavigation> {
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    // Hive.registerAdapter(PasswordModelAdapter());
    _openBox();
  }

  Future _openBox() async {
    WidgetsFlutterBinding.ensureInitialized();
    var dir = await getApplicationDocumentsDirectory();
    Hive.init(dir.path);
    passwordBox = await Hive.openBox<PasswordModel>('passwordBox');
    return;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Column(
      children: [
        WatchBoxBuilder(
          box: passwordBox,
          builder: (context, box) {
            Map<dynamic, dynamic> raw = box.toMap();
            List list = raw.values.toList();

            return ListView.builder(
              shrinkWrap: true,
              itemCount: list.length,
              itemBuilder: (context, index) {
                PasswordModel passwordModel = list[index];
                return ListTile(
                  title: Text(passwordModel.websiteName),
                  subtitle: Text(passwordModel.websiteAddress),
                );
              },
            );
          },
        ),
      ],
    ));
  }
}

Upvotes: 0

Views: 5607

Answers (2)

Ismail Shah
Ismail Shah

Reputation: 83

Replace this ' passwordBox = await Hive.openBox<PasswordModel>('passwordBox');

with this passwordBox = await Hive.openBox<PasswordModel>('passwordBox'); passwordBox = Hive.box<PasswordModel>('passwordBox');

Upvotes: 0

Marcel
Marcel

Reputation: 9569

I takes some time to open boxes, that's why Hive.openBox returns a Future. The reason is that their content still needs to be loaded into memory. So, the first time your widget is displayed, it opens the box, but it takes some time before the variable is initialized.

You'll have to think about what to show to the user in the meantime:

Widget build(BuildContext context) {
  if (someBox == null) {
    return CircularProgressIndicator();
  }
  // Here, you can use the box.
  ...
}

Btw, I wouldn't recommend storing the boxes in global variables, because that can get messy quickly. Using Hive, you only need to call openBox once. Then, you can get a reference to the box synchronously using Hive.box.

So, you could also instead call Hive.openBox() in your main-method before calling runApp. The app will then take a moment longer to start, but you'll have the data readily available everywhere you need it:

void main() {
  await Hive.openBox('my-box');
  runApp(MyApp());
}

// elsewhere:
Widget build(BuildContext context) {
  var box = Hive.box('my-box');
  ...
}

For more sophisticated state management, the State Management video from the last Google I/O might also be of interest to you.

Upvotes: 1

Related Questions