How to load data to Flutter DataTable (SfDataGrid) with Hive box?
Load the data from the hive database to the Flutter DataTable widget by fetching the list collection from the hive database, and create the rows for the Datagrid from that list collection.
The following steps explain how to load the data from the hive database to the Flutter DataTable.
STEP 1: To access the hive database, add the following dependencies in pubspec.yaml.
dependencies: hive_flutter: ^1.0.0 get: ^4.1.3 flutter_secure_storage: ^3.3.5 hive: ^2.0.0 path_provider: ^2.0.1 dev_dependencies: hive_generator: ^1.0.0 build_runner: ^1.11.5
STEP 2: Import the following libraries in the Flutter application.
import 'dart:convert'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart';
STEP 3: Create the class with the required properties that are given in the hive database, and add proper hive annotations for generating type adaptors. Here, we have explained with simple Employee class.
import 'package:hive/hive.dart'; @HiveType(typeId: 0) class Employee { @HiveField(0) int id; @HiveField(1) String name; @HiveField(2) String designation; @HiveField(3) int salary; Employee( this.id, this.name, this.designation, this.salary, ); }
STEP 4: Create a hive database. Open the hive box before performing any operation in the database. Open the hive box using Hive.openBox (‘DataBase name’) method. Here we have created a hive database for fetching data from the database, and performing CRUD operation.
class EmployeeDatabase extends GetxController { String boxName = 'employee_database'; List<Employee> employeeList = []; Future<Box<Employee>> encryptedBox() async { final FlutterSecureStorage secureStorage = const FlutterSecureStorage(); var containsEncryptionKey = await secureStorage.containsKey(key: 'key'); if (!containsEncryptionKey) { var key = Hive.generateSecureKey(); await secureStorage.write(key: 'key', value: base64UrlEncode(key)); } var encryptionKey = base64Url.decode(await secureStorage.read(key: 'key')); var box = await Hive.openBox<Employee>(boxName, encryptionCipher: HiveAesCipher(encryptionKey)); return box; } void loadEmployeeData() async { var box = await Hive.openBox<Employee>(boxName); box.put(0, Employee(10001, 'Lara', 'Manager', 30000)); box.put(1, Employee(10002, 'Kathryn', 'Manager', 30000)); box.put(2, Employee(10003, 'Lara', 'Developer', 15000)); box.put(3, Employee(10004, 'Michael', 'Designer', 15000)); box.put(4, Employee(10005, 'Martin', 'Developer', 15000)); box.put(5, Employee(10006, 'Newberry', 'Developer', 15000)); box.put(6, Employee(10007, 'Balnc', 'Developer', 15000)); box.put(7, Employee(10008, 'Perry', 'Developer', 15000)); box.put(8, Employee(10009, 'Gable', 'Developer', 15000)); box.put(9, Employee(10010, 'Grimes', 'Developer', 15000)); } void addEmployee(Employee newEmployee) async { var box = await Hive.openBox<Employee>(boxName); await box.add(newEmployee); employeeList = box.values.toList(); refresh(); } void getEmployees() async { var box = await Hive.openBox<Employee>(boxName); employeeList = box.values.toList(); refresh(); } List<Employee> getEmployeesList() { getEmployees(); return employeeList; } void updateEmployee({Employee employee, int key}) async { var box = await Hive.openBox<Employee>(boxName); await box.putAt(key, employee); employeeList = box.values.toList(); refresh(); } void deleteEmployee(key) async { var box = await Hive.openBox<Employee>(boxName); await box.deleteAt(key); employeeList = box.values.toList(); refresh(); } }
STEP 5: Create class for TypeAdaptor. Here we have created a custom TypeAdaptor for the Employee class.
import 'package:hive/hive.dart'; import 'employee.dart'; class EmployeeAdaptor extends TypeAdapter<Employee> { @override final int typeId = 0; @override Employee read(BinaryReader reader) { final numOfFields = reader.readByte(); final fields = <int, dynamic>{ for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return Employee( fields[0] as int, fields[1] as String, fields[2] as String, fields[3] as int, ); } @override void write(BinaryWriter writer, Employee obj) { writer ..writeByte(4) ..writeByte(0) ..write(obj.id) ..writeByte(1) ..write(obj.name) ..writeByte(2) ..write(obj.designation) ..writeByte(3) ..write(obj.salary); } @override int get hashCode => typeId.hashCode; @override bool operator ==(Object other) => identical(this, other) || other is EmployeeAdaptor && runtimeType == other.runtimeType && typeId == other.typeId; }
STEP 6: Register the type adapter in the main function, and add the hive initialization.
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Hive.initFlutter(); Hive.registerAdapter(EmployeeAdaptor()); runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', home: EmployeeListScreen(), ); } }
STEP 7: Create an EmployeeDataGridSource class which extends with the DataGridSource, to create the collection of the DataGridRow for the SfDataGrid.
class EmployeeDataSource extends DataGridSource { EmployeeDataSource({this.employeeDatabase}) { initialLoading(); employeeDatabase.addListener(handleListUpdates); } EmployeeDatabase employeeDatabase; List<Employee> employeeData = []; List<DataGridRow> _employeeDataGridRow = []; void initialLoading() { employeeData = employeeDatabase.getEmployeesList(); buildDataGridRows(); } void handleListUpdates() { employeeData = employeeDatabase.employeeList; buildDataGridRows(); notifyListeners(); } void buildDataGridRows() { _employeeDataGridRow = employeeData .map<DataGridRow>( (employee) => DataGridRow( cells: [ DataGridCell<int>(columnName: 'id', value: employee.id), DataGridCell<String>(columnName: 'name', value: employee.name), DataGridCell<String>( columnName: 'designation', value: employee.designation), DataGridCell<int>(columnName: 'salary', value: employee.salary), ], ), ) .toList(); } void updateDataGridSource() { notifyListeners(); } @override List<DataGridRow> get rows => _employeeDataGridRow; @override DataGridRowAdapter buildRow(DataGridRow row) { return DataGridRowAdapter( cells: row.getCells().map<Widget>((e) { return Container( alignment: Alignment.center, padding: EdgeInsets.all(8.0), child: Text(e.value.toString()), ); }).toList()); } }
STEP 8: Wrap the SfDataGrid inside the GetBuilder widget. Initialize the SfDataGrid with all the required details. Here we have provided the option to perform the crud operation with the hive database.
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('DataGrid Sample'), backgroundColor: Colors.blue, actions: [ MaterialButton( onPressed: () { showAddEmployee(context); }, child: Icon(Icons.add), ), MaterialButton( onPressed: () { showDeleteEmployee(context); }, child: Icon(Icons.delete), ), ], ), body: GetBuilder<EmployeeDatabase>( builder: (database) { return SfDataGrid( source: dataGridSource, onCellTap: (DataGridCellTapDetails tapDetails) { if (tapDetails.rowColumnIndex.rowIndex == 0) { return; } showUpdateEmployees( context, tapDetails.rowColumnIndex.rowIndex); }, columnWidthMode: ColumnWidthMode.fill, columns: getColumns()); }, ), ); } }
View example in GitHub.