I'm working on a flutter app, I'll start by saying that I'm a beginner and I'm at the beginning of mobile development, I'm using the Hive to store data on the device, while debugging I saw that when I add data, the hive is updated correctly, but when I close and restart the app I lose everything, below I will put the code of the main class that opens the box and of another class that uses the hive to store the data, the other classes of the project do not touch the hive , can someone help me?
main class:
import 'package:flutter/material.dart';
import 'package:todo/pages/home_page.dart';
import 'package:hive_flutter/hive_flutter.dart';
void main() async {
//init the hive
await Hive.initFlutter();
//open a box
var box = await Hive.openBox('myBox');
//run the app
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
theme: ThemeData(primarySwatch: Colors.purple),
);
}
}
HomePage class:
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:todo/pages/topic_page.dart';
import 'package:todo/util/dialog_box.dart';
import 'package:todo/util/topic_tile.dart';
class Topic {
String topicName;
List todo = [
["Add your first To-Do", false]
];
Topic(this.topicName);
void addTodo(List todoList) {
todo.add(todoList);
}
void removeTodo(int index) {
todo.removeAt(index);
}
String getName() {
return topicName;
}
List getTodo() {
return todo;
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//reference the box
final _myBox = Hive.box('mybox');
//text controller
final _controller = TextEditingController();
//Database
List topic = [];
@override
void initState() {
if (_myBox.get("TOPIC") != null) {
topic = _myBox.get("TOPIC");
}
super.initState();
}
//update the topic
void updateTopic() {
_myBox.put("TOPIC", topic);
}
//save new task
void saveNewTopic() {
setState(() {
topic.add(Topic(_controller.text));
_controller.clear();
});
Navigator.of(context).pop();
}
//new topic function
void createNewTopic() {
showDialog(
context: context,
builder: (context) {
return DialogBox(
text: "Add a new topic",
controller: _controller,
onSave: saveNewTopic,
onCancel: () => Navigator.of(context).pop(),
);
});
updateTopic();
}
//delete task
void deleteTopic(int index) {
setState(() {
topic.removeAt(index);
});
updateTopic();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color.fromARGB(255, 255, 190, 93),
appBar: AppBar(
title: const Align(
alignment: Alignment.center,
child: Text(
"Topic",
style: TextStyle(fontSize: 32, color: Colors.white),
))),
floatingActionButton: FloatingActionButton(
onPressed: createNewTopic,
child: Icon(Icons.add),
),
body: ListView.builder(
itemCount: topic.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TopicPage(topic: topic[index]),
),
);
},
child: TopicTile(
topicName: topic[index].getName(),
deleteFunction: (context) => deleteTopic(index),
),
);
}));
}
}
As I was running an example project with this part of your code, to recreate the bug, when I tapped on the floating action button to add the second item, I got this error:
E/flutter ( 1691): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: HiveError: Cannot write, unknown type: Topic. Did you forget to register an adapter?
E/flutter ( 1691): #0 BinaryWriterImpl.write (package:hive/src/binary/binary_writer_impl.dart:338:9)
E/flutter ( 1691): #1 BinaryWriterImpl.writeList (package:hive/src/binary/binary_writer_impl.dart:223:7)
E/flutter ( 1691): #2 BinaryWriterImpl._writeList (package:hive/src/binary/binary_writer_impl.dart:390:7)
E/flutter ( 1691): #3 BinaryWriterImpl.write (package:hive/src/binary/binary_writer_impl.dart:329:7)
E/flutter ( 1691): #4 BinaryWriterImpl.writeFrame (package:hive/src/binary/binary_writer_impl.dart:282:9)
E/flutter ( 1691): #5 StorageBackendVm.writeFrames.<anonymous closure> (package:hive/src/backend/vm/storage_backend_vm.dart:128:31)
E/flutter ( 1691): #6 ReadWriteSync.syncWrite.<anonymous closure> (package:hive/src/backend/vm/read_write_sync.dart:26:41)
E/flutter ( 1691): <asynchronous suspension>
E/flutter ( 1691): #7 BoxImpl._writeFrames (package:hive/src/box/box_impl.dart:88:7)
E/flutter ( 1691): <asynchronous suspension>
E/flutter ( 1691):
Looks like you have forgotten to register the adapter for your custom object. Because hive needs you to register an adapter for any custom object that is put into it. An example can be found here: Hive Objects. We can move the Topic
class to a new file and update the code to:
import 'package:hive_flutter/hive_flutter.dart';
part 'topic.g.dart';
@HiveType(typeId: 1) // <-- this is a hive object
class Topic extends HiveObject {
@HiveField(0) // <-- hive field
String topicName;
@HiveField(1) // <-- hive field
List todo = [
["Add your first To-Do", false]
];
Topic(this.topicName);
void addTodo(List todoList) {
todo.add(todoList);
}
void removeTodo(int index) {
todo.removeAt(index);
}
String getName() {
return topicName;
}
List getTodo() {
return todo;
}
}
Then we will get an error on this line:
part 'topic.g.dart';
Because we should generate the this file (which contains the adapter). so we execute this command in our project folder:
dart run build_runner build
Now we can see the error is gone. After generating the adapter, we add it in the main.dart
file like so:
void main() async {
//init the hive
await Hive.initFlutter();
// register the adapter for the Topic hive object
Hive.registerAdapter(TopicAdapter()); // <-- this line right here
//open a box
await Hive.openBox('myBox');
runApp(const MyApp());
}
Finally we can re-run the app and see that it works as expected.
Full tutorial for storing custom objects can be found here.