Insert SQL data in Flutter

With the help of SQLite database in accordance with future, await, and async we can insert, retrieve, update, or delete data in Flutter.

In this section, we’ll take a look at how we can insert data to SQL database and display them. As we progress, we’ll learn the other techniques to update and delete data.

It is preferable to use SQLite database in Flutter, because it is faster than local file. 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 Future, await and async 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.

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 to insert data in SQL database in Flutter?

Firstly, we need a Text Controller to type on the screen. Right?

Then, we need a Text Button to press, so that that piece of data will be inserted into the SQLite database.

Secondly, we need to add the dependency.

dependencies:
  cupertino_icons: ^1.0.2
  flutter:
    sdk: flutter
  intl: ^0.17.0
  path_provider: ^2.0.8
  provider: ^6.0.1
  sqflite:

Next, we need a model data class and Database Handler helper class that will connect our SQLite database to the model data class.

First, data model class.

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

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

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

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

We need to map that data model class so that later we can work on it in Flutter.

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.

Why?

Because, the database helper class will provide the methods that will create the database table, and help us to insert and retrieve data from SQLite database.

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, 'usersix.db'),
      onCreate: (database, version) async {
        await database.execute(
          "CREATE TABLE usersix(id INTEGER PRIMARY KEY AUTOINCREMENT, name 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('usersix', user.toMap());
    }
    return result;
  }

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

It’s a good practice that we break down these code snippets and keep this data model and helper class in our model folder inside lib folder.

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.

Our next challenge is to show a text field to the user so that she can type any text and press the button.

Inserting data in SQLite database in Flutter
Inserting data in SQLite database in Flutter

At the same page we need to show the Navigate button, that will take us to another screen where the inserted data will be displayed.

Data is being inserted in SQLite database in Flutter
Data is being inserted in SQLite database in Flutter
import 'package:flutter/material.dart';
import 'package:flutter_data_and_backend/view/future_dark.dart';

import 'model/user.dart';

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

/// we're now in branch six
///
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'data',
      home: MyAppHome(),
    );
  }
}

class MyAppHome extends StatefulWidget {
  const MyAppHome({Key? key}) : super(key: key);

  @override
  State<MyAppHome> createState() => _MyAppHomeState();
}

class _MyAppHomeState extends State<MyAppHome> {
  final List<User> usersList = [];

  final nameController = TextEditingController();

  void addName(String name) {
    final user = User(
      name: name,
    );
    setState(() {
      usersList.add(user);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Inserting Data'),
        actions: <Widget>[
          IconButton(
            icon: const Icon(Icons.add_alert),
            tooltip: 'Show Snackbar',
            onPressed: () {
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(
                  content: Text('A SnackBar'),
                ),
              );
            },
          ),
          IconButton(
            icon: const Icon(Icons.search_outlined),
            tooltip: 'Search',
            onPressed: () {
              // our code
            },
          ),
        ],
      ),
      body: Center(
        child: Column(
          children: [
            Container(
              padding: const EdgeInsets.all(5),
              child: Card(
                elevation: 10,
                child: Column(
                  children: [
                    TextField(
                      decoration: const InputDecoration(
                        border: OutlineInputBorder(),
                        labelText: 'ITEM',
                        suffixStyle: TextStyle(
                          fontSize: 50,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      controller: nameController,
                    ),
                    TextButton(
                      onPressed: () {
                        addName(
                          nameController.text,
                        );
                      },
                      child: const Text(
                        'SUBMIT',
                        style: TextStyle(
                          fontSize: 25,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                    const SizedBox(
                      height: 5,
                    ),
                  ],
                ),
              ),
            ),
            NavigationWidget(usersList: usersList),
          ],
        ),
      ),
    );
  }
}

class NavigationWidget extends StatelessWidget {
  const NavigationWidget({
    Key? key,
    required this.usersList,
  }) : super(key: key);

  final List<User> usersList;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        padding: const EdgeInsets.all(5),
        height: 150,
        width: 350,
        child: Column(
          children: usersList.map((e) {
            return Column(
              children: [
                TextButton(
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => FutureDark(
                          name: e.name,
                        ),
                      ),
                    );
                  },
                  child: const Text(
                    'Navigate',
                    style: TextStyle(
                      fontSize: 30.0,
                      fontWeight: FontWeight.bold,
                      color: Colors.redAccent,
                    ),
                  ),
                ),
              ],
            );
          }).toList(),
        ),
      ),
    );
  }
}

The above code could be broken down to more pages or screens using more custom widgets.

Data from SQLite database is being shown on Flutter screen
Data from SQLite database is being shown on Flutter screen

However, in one place will help us to understand the mechanism of how we have used Text Controller, Text Button and a Material Page Route to insert data and after that, we can see them.

Second Data from SQLite database is being shown on Flutter screen
Second Data from SQLite database is being shown on Flutter screen

How to retrieve data from SQLite database in Flutter?

Retrieving data from SQLite database is much easier than inserting data.

With the help of Future API, async, await keywords, and then functions and FutureBuilder widget, we can do that.

At the same screen we also catch the data or list item that we’ve sent from the home page.

import 'package:flutter/material.dart';

import 'package:flutter_data_and_backend/model/database_handler.dart';
import 'package:flutter_data_and_backend/model/user.dart';

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

  final String name;

  @override
  State<FutureDark> createState() => _FutureDarkState();
}

class _FutureDarkState extends State<FutureDark> {
  DatabaseHandler? handler;
  @override
  void initState() {
    List<User> users = [
      User(name: widget.name.toString()),
    ];
    Future<int> addUsers() async {
      return await handler!.insertUser(users);
    }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Showing Data'),
      ),
      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,
                    ),
                  ),
                );
              },
            );
          } else {
            return const Center(child: CircularProgressIndicator());
          }
        },
      ),
    );
  }
}

The Future Builder is a widget that builds itself based on the latest snapshot of interaction with a Future.

We’ve obtained the future must have been obtained earlier, during State.initStateState.didUpdateWidget, or State.didChangeDependencies.

FutureBuilder must not be created during the State.build or StatelessWidget.build method call when constructing the FutureBuilder.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

Courses at Educative

GitHub repository

Technical blog

Twitter

Comments

One response to “Insert SQL data in Flutter”

  1. […] going to learn how we can build a SQLite Blog Application in Flutter. As it sounds, a Blog App must fulfill some […]

Leave a Reply