Which database we use in Flutter

We can use SQLite database in Flutter. However, we need to use a special package or plugin sqflite which is available in pub.dev. We also need to use Future API, async, await keywords, and then functions to make it successful.

We’ve discussed this feature for absolute beginners in previous section, is Flutter single thread?

Anyway, as a result, the sqflite package provides classes and functions to interact with a SQLite database. Moreover, using SQLite database is better than using a local file, or key-value store.

There are reasons to do that.

SQLite database provides faster CRUD. That is, we can create, retrieve, update and delete data. And, it’s always better than the local persistent solutions.

In this section we’ll see how we can create a users table in our SQLite database, and retrieve that data on our Flutter application.

It will be a gentle introduction to SQLite database with Flutter. We’ll see how we can create a database, insert some data and after that, retrieve them.

Later as we progress, we’ll see how we can improve the other functionalities. To get the code snippets used in this section, we have a respective GitHub repository. If you have interest, please download and run the code.

Besides sqflite package, we need to use another package path, that will define the location for storing the database on the disk.

For the beginners, here is a guide what SQLite database is.

What is SQLite database?

SQLite is a C-language library that implements many features at one go. It is smallfastself-containedhigh-reliabilityfull-featured, SQL database engine.

By the way, SQLite is the most used database engine in the world. Besides, SQLite database file format is stable, cross-platform, and backwards compatible.

There are over 1 trillion SQLite databases in active use at present.

Therefore, let’s go ahead and make our first Flutter Application with SQLite database.

How do you make a database on Flutter app?

Let’s add the dependencies in our pubspec.yaml file first.

dependencies:
  flutter:
    sdk: flutter
  sqflite: 
  path: 

After that, create a model folder, inside lib folder, and create one user class and a database helper class there.

Firstly, let’s take a look at the user model class.

class User {
  final int? id;
  final String name;
  final String location;

  User({
    this.id,
    required this.name,
    required this.location,
  });

  User.fromMap(Map<String, dynamic> res)
      : id = res["id"],
        name = res["name"],
        location = res["location"];

  Map<String, Object?> toMap() {
    return {
      'id': id,
      'name': name,
      'location': location,
    };
  }
}

To get data stored in SQLite database, we need to convert them to a map. The reason is simple. After all, in our Flutter Application we need to convert them to a list of items.

That’s why we have created a named constructor User.fromMap() and a method toMap().

Secondly, we’ll create a table with the help of the helper class.

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

import 'user.dart';

class DatabaseHandler {
  Future<Database> initializeDB() async {
    String path = await getDatabasesPath();
    return openDatabase(
      join(path, 'usersfirst.db'),
      onCreate: (database, version) async {
        await database.execute(
          "CREATE TABLE usersfirst(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, location TEXT NOT NULL)",
        );
      },
      version: 1,
    );
  }

  Future<int> insertUser(List<User> users) async {
    int result = 0;
    final Database db = await initializeDB();
    for (var user in users) {
      result = await db.insert('usersfirst', user.toMap());
    }
    return result;
  }

  Future<List<User>> retrieveUsers() async {
    final Database db = await initializeDB();
    final List<Map<String, Object?>> queryResult = await db.query('usersfirst');
    return queryResult.map((e) => User.fromMap(e)).toList();
  }
}

The method getDatabasePath() of sqflite package will get the default database location. However, the join() method is inside the package path that will join the given path into a single path.

As a matter of fact, two packages sqflite and path are necessary for this reason.

In addition, to keep our first Flutter SQLite database application simple, we’re going to create, insert, and retrieve the users. We’ll add the list of users manually in our main method.

Now, we’re going to display the users data.

import 'package:flutter/material.dart';

import 'model/database_handler.dart';
import 'model/user.dart';

void main() {
  runApp(const MyApp());
}

/// adding first branch
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter smimple database',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter smimple database'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late DatabaseHandler handler;

  @override
  void initState() {
    Future<int> addUsers() async {
      User firstUser = User(name: "Mana", location: "Nabagram");
      User secondUser = User(name: "Babu", location: "Nabagram");
      User thirdUser = User(name: "Pata", location: "Nabagram");
      List<User> listOfUsers = [
        firstUser,
        secondUser,
        thirdUser,
      ];
      return await handler.insertUser(listOfUsers);
    }

    super.initState();
    handler = DatabaseHandler();
    handler.initializeDB().whenComplete(() async {
      await addUsers();
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: FutureBuilder(
        future: handler.retrieveUsers(),
        builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
          if (snapshot.hasData) {
            return ListView.builder(
              itemCount: snapshot.data?.length,
              itemBuilder: (BuildContext context, int index) {
                return Card(
                  child: ListTile(
                    key: ValueKey<int>(snapshot.data![index].id!),
                    contentPadding: const EdgeInsets.all(8.0),
                    title: Text(
                      snapshot.data![index].name,
                      style: Theme.of(context).textTheme.headline3,
                    ),
                    subtitle: Text(
                      snapshot.data![index].location.toString(),
                      style: Theme.of(context).textTheme.headline5,
                    ),
                  ),
                );
              },
            );
          } else {
            return const Center(child: CircularProgressIndicator());
          }
        },
      ),
    );
  }
}

Next, we create an instance of class DatabaseHandler first. With the help of the database handler object we can call initalizeDb() method to create the SQLite database.

We know that Future in Flutter or Dart gives us a promise token and says that a value will be returned at some point in future. Therefore, when Future is completed, addUsers() method is called.

Consequently, the addUsers() method calls insertUsers() method to insert the list of users to the SQLite database.

Next, the FutureBuilder widget builds itself based on the latest snapshot of interaction with a Future. Moreover, unless the Future is completed, it gives us the uncompleted state which shows a circular progress indicator.

Flutter application retrieves data from SQLite database with FutureBuilder

However, when the value is returned in Future, it retrieves data from SQLite database successfully.

FutureBuilder retrieves data from SQLite database in Flutter
FutureBuilder retrieves data from SQLite database in Flutter

By the way, we’ve added this list of users manually.

 Future<int> addUsers() async {
      User firstUser = User(name: "Mana", location: "Nabagram");
      User secondUser = User(name: "Babu", location: "Nabagram");
      User thirdUser = User(name: "Pata", location: "Nabagram");
      List<User> listOfUsers = [
        firstUser,
        secondUser,
        thirdUser,
      ];
      return await handler.insertUser(listOfUsers);
    }

In the next section, we’ll try to implement other features of CRUD in our Flutter Application.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

GitHub repository

Technical blog

Twitter

Comments

3 responses to “Which database we use in Flutter”

  1. […] SQLite database should allow us to insert, update or delete data. Moreover, we need to retrieve data as […]

  2. […] we use SQLite database with Provider package in Flutter? The answer is, yes! We […]

  3. […] section has discussed the application structure. In this second part, we’ll concentrate on database connection, data model […]

Leave a Reply