How to make contact manager app to store data permanently

make your Contact Manager app store data permanently.
That means, even if you close the app and reopen, contacts will still be there.

Flutter has two common storage options:

  1. SQLite → Relational database (like MySQL/PostgreSQL).
    • Best for structured data (tables, queries).
    • Needs sqflite package.
  2. Hive → NoSQL, very fast, stores key–value pairs/objects.
    • Best for simple apps.
    • No SQL queries needed.

Since you’re just starting, I’ll teach you Hive first (easier). Later we can do SQLite.


Step 1: Add Hive to Your Project

Open pubspec.yaml and add dependencies:

dependencies:
  flutter:
    sdk: flutter
  hive: ^2.2.3
  hive_flutter: ^1.1.0

dev_dependencies:
  hive_generator: ^2.0.0
  build_runner: ^2.4.8

Run:

flutter pub get

Step 2: Initialize Hive in main.dart

import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize Hive
  await Hive.initFlutter();

  // Open a box (like a database table)
  await Hive.openBox('contactsBox');

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const ContactManager(),
    );
  }
}

Step 3: Use Hive Box for CRUD

class ContactManager extends StatefulWidget {
  const ContactManager({super.key});

  @override
  State<ContactManager> createState() => _ContactManagerState();
}

class _ContactManagerState extends State<ContactManager> {
  final TextEditingController nameController = TextEditingController();
  final TextEditingController emailController = TextEditingController();

  final contactsBox = Hive.box('contactsBox');

  // Add Contact
  void addContact() {
    contactsBox.add({
      "name": nameController.text,
      "email": emailController.text,
    });
    nameController.clear();
    emailController.clear();
  }

  // Update Contact
  void updateContact(int index, Map contact) {
    nameController.text = contact["name"];
    emailController.text = contact["email"];

    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text("Update Contact"),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            TextField(controller: nameController, decoration: const InputDecoration(labelText: "Name")),
            TextField(controller: emailController, decoration: const InputDecoration(labelText: "Email")),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () {
              contactsBox.putAt(index, {
                "name": nameController.text,
                "email": emailController.text,
              });
              nameController.clear();
              emailController.clear();
              Navigator.pop(context);
            },
            child: const Text("Update"),
          ),
        ],
      ),
    );
  }

  // Delete Contact
  void deleteContact(int index) {
    contactsBox.deleteAt(index);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Contact Manager")),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(controller: nameController, decoration: const InputDecoration(labelText: "Name")),
            TextField(controller: emailController, decoration: const InputDecoration(labelText: "Email")),
            const SizedBox(height: 10),
            ElevatedButton(
              onPressed: addContact,
              child: const Text("Add Contact"),
            ),
            const SizedBox(height: 20),

            // Contacts List (auto updates when box changes)
            Expanded(
              child: ValueListenableBuilder(
                valueListenable: contactsBox.listenable(),
                builder: (context, box, _) {
                  return ListView.builder(
                    itemCount: box.length,
                    itemBuilder: (context, index) {
                      final contact = box.getAt(index) as Map;
                      return Card(
                        child: ListTile(
                          title: Text(contact["name"]),
                          subtitle: Text(contact["email"]),
                          trailing: Row(
                            mainAxisSize: MainAxisSize.min,
                            children: [
                              IconButton(
                                icon: const Icon(Icons.edit, color: Colors.blue),
                                onPressed: () => updateContact(index, contact),
                              ),
                              IconButton(
                                icon: const Icon(Icons.delete, color: Colors.red),
                                onPressed: () => deleteContact(index),
                              ),
                            ],
                          ),
                        ),
                      );
                    },
                  );
                },
              ),
            )
          ],
        ),
      ),
    );
  }
}

What Changed?

  • Instead of using a List, we use Hive Box (contactsBox).
  • add() → inserts new contact.
  • putAt() → updates contact at index.
  • deleteAt() → deletes contact.
  • ValueListenableBuilder → auto-refresh UI when data changes.
  • Data is saved permanently in your device storage.



Leave a Reply