Flutter SQFlite Tutorial and Examples

How to work with SQLite datbase in flutter.

What is Flutter?

Flutter is Google’s mobile app SDK for crafting high-quality native interfaces on iOS and Android in record time.

Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.

How To Easily Use Flutter Wrap Widget – Flutter Example Code

How To Easily Use Flutter Wrap Widg...
How To Easily Use Flutter Wrap Widget – Flutter Example Code

Here are the three main features of Flutter:

1. Fast Development

Flutter can paint your app to life in milliseconds through hot Reload.

You can alos employ a rich set of fully-customizable widgets to build native interfaces in minutes.

2. Expressive and Flexible UI

Flutter allows you to quickly ship features with a focus on native end-user experiences.

Layered architecture allows full customization, which results in incredibly fast rendering and expressive and flexible designs.

3. Native Performance

Flutter’s widgets incorporate all critical platform differences such as scrolling, navigation, icons and fonts to provide full native performance on both iOS and [Android](/android/introduction.

What is SQFlite?

SQflite is a plugin for flutter. It allows us store, retrieve and manipulate our SQLite databases via flutter code. SQflite supports both Android and iOS platforms.

Here are some of the features of SQFlite:

  1. SQFlite provides for both database transactions as well as batches.
  2. SQlite has inbuilt automatic version managment.
  3. SQFlite provides easy to use methods for inserting, querying, updating as well as deleting data from database.
  4. These CRUD operations are performed in the background thread on both iOS and Android. This frees the UI to remain responsive.

How to Install SQFlite

SQFlite installation is as easy as any other flutter packages. It's hosted inDart Package Repository and can be added as a dependenncy.

To do that:

1. Go to Your pubspec.yaml file:

And add it as a dependency:

dependencies:
  sqflite: ^0.12.1

You may check the latest version here.

2. Download it

Android Studio will provide you with a package get button which will fetch it and add to your project as long as you are online.

If you are using Visual Studio code then making a change in the pubspec.yaml file will cause the flutter packages get command to be automatically invoked.

Otherwise if you are not using the IDE's above then you can install it from the command line

$ flutter packages get

3. Import into You Project

Go over to your dart code where you want to use it and import it at the top of your file.

import 'package:sqflite/sqflite.dart';

Quick Flutter SQFLite Database HowTo Snippets

1. How to get Database Path

        // Check if we have an existing copy first
        var databasesPath = await getDatabasesPath();
        String path = join(databasesPath, "demo_asset_example.db");

2. How to Open a Database

        // try opening (will work if it exists)
        Database db;
        try {
          db = await openDatabase(path, readOnly: true);
        } catch (e) {
          print("Error $e");
        }

You can put in a helper class:

class Helper {
  final String path;
  Helper(this.path);
  Database _db;
  final _lock = Lock();

  Future<Database> getDb() async {
    if (_db == null) {
      await _lock.synchronized(() async {
        // Check again once entering the synchronized block
        if (_db == null) {
          _db = await openDatabase(path);
        }
      });
    }
    return _db;
  }

Or:

  Future<Database> get db async {
    if (_db != null) return _db;
    _db = await initDb();
    return _db;
  }

whereby initDb() is a custom method to obtain us the path and open it as:

  initDb() async {
    io.Directory documentsDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentsDirectory.path, "test.db");
    var theDb = await openDatabase(path, version: 1, onCreate: _onCreate);
    return theDb;
  }

3. How to Create a Database Table

Let's see how we can create a database table in flutter with S

      var db = await openDatabase(path);
      await db.execute("CREATE TABLE IF NOT EXISTS Test(id INTEGER PRIMARY KEY)");

or:

  void _onCreate(Database db, int version) async {
    // When creating the db, create the table
    await db.execute(
        "CREATE TABLE Employee(id INTEGER PRIMARY KEY, firstname TEXT, lastname TEXT, mobileno TEXT,emailId TEXT )");
    print("Created tables");
  }

The db is the Database object. We invoke it's execute() method and pass in our raw sql statement to create us the table.

4. How to Insert into a database table

      await db.insert("Test", {"id": 1});

or:

  Future<int> insertTodo(Todo todo) async {
    Database db = await this.db;
    var result = await db.insert(tblTodo, todo.toMap());
    return result;
  }

or let's say I want to insert a Person with his properties into Database, then return the inserted person:

  Future insertPerson(Person person) async {
    person.id = await _db.insert("people", person.toMap());
    return person;
    }

or

  void saveEmployee(Employee employee) async {
    var dbClient = await db;
    await dbClient.transaction((txn) async {
      return await txn.rawInsert(
          'INSERT INTO Employee(firstname, lastname, mobileno, emailid ) VALUES(' +
              ''' +
              employee.firstName +
              ''' +
              ',' +
              ''' +
              employee.lastName +
              ''' +
              ',' +
              ''' +
              employee.mobileNo +
              ''' +
              ',' +
              ''' +
              employee.emailId +
              ''' +
              ')');
    });
  }

5. How to Query or Select From SQLite Table

      await db.query("Test")

Say I want to return a select and return a list of People from the database:

    Future fetchEveryone() async {
    List results = await _db.query("people", columns: Person.columns);
    List people = new List();
    results.forEach((map) {
      people.add(Person.fromMap(map));
    });
    return people;
    }

Or say we want to query a list our SQlite database in flutter and populate a List. We can also use a raw query using the rawQuery method. You pass into it the SQL statement to be executed.

  Future<List<Employee>> getEmployees() async {
    var dbClient = await db;
    List<Map> list = await dbClient.rawQuery('SELECT * FROM Employee');
    List<Employee> employees = new List();
    for (int i = 0; i < list.length; i++) {
      employees.add(new Employee(list[i]["firstname"], list[i]["lastname"], list[i]["mobileno"], list[i]["emailid"]));
    }
    print(employees.length);
    return employees;
  }

Or another example:

  Future<List> getTodos() async {
    Database db = await this.db;
    var result = await db.rawQuery("SELECT * FROM $tblTodo ORDER BY $colPriority ASC");
    return result;
  }

Let's say I want to check if a user is logged in:

  Future<bool> isLoggedIn() async {
    var dbClient = await db;
    var res = await dbClient.query("User");
    return res.length > 0 ? true : false;
  }

7 . How to Count number of items in SQLite

  Future<int> getCount() async {
    Database db = await this.db;
    var result = Sqflite.firstIntValue(
      await db.rawQuery("SELECT COUNT (*) FROM $tblTodo")
    );
    return result;
  }

7. How to Update Data in SQLite database using SQFLite

  Future<int> updateTodo(Todo todo) async {
    var db = await this.db;
    var result = await db.update(tblTodo, todo.toMap(),
      where: "$colId = ?", whereArgs: [todo.id]);
    return result;
  }

7. How to Delete From SQLite database using SQFLite

  Future<int> deleteTodo(int id) async {
    int result;
    var db = await this.db;
    result = await db.rawDelete('DELETE FROM $tblTodo WHERE $colId = $id');
    return result;
  }

Or:

  Future<int> deleteUsers() async {
    var dbClient = await db;
    int res = await dbClient.delete("User");
    return res;
  }

6. How to Close Database

      await db.close();

Or:

  Future close() async {
    await _db.close();
  }

Full Examples

Let's now look at some full examples involving Flutter SQFlite.

(a). Flutter SQFLite – INSERT,SELECT,SHOW

This is a simple Dart Flutter Example Tutorial demonstrating how to perform basic CRUD: Insert, Select and Show data in a flutter application. We will be using the SQFLite SQLite plugin. This is because our database is the SQLite

Full Example Project

Here's the full source code.

(a). pubspec.yaml

Our dependencies:

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^0.1.2
  path_provider: '>=0.3.0'
  sqflite: any

dev_dependencies:
  flutter_test:
    sdk: flutter

(b). employee.dart

A dart class to represent a single employee with firstname, lastname,mobile number and email as properties. These properties will be received via the constructor:

class Employee {
  String firstName;
  String lastName;
  String mobileNo;
  String emailId;

  Employee(this.firstName, this.lastName, this.mobileNo, this.emailId);
  Employee.fromMap(Map map) {
    firstName = map[firstName];
    lastName = map[lastName];
    mobileNo = map[mobileNo];
    emailId = map[emailId];
  }
}

(c). dbhelper.dart

A DBHelper class to help with implementation of database crud operations:

import 'dart:async';
import 'dart:io' as io;
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_crud/model/employee.dart';

class DBHelper {
  static Database _db;

  Future<Database> get db async {
    if (_db != null) return _db;
    _db = await initDb();
    return _db;
  }

  initDb() async {
    io.Directory documentsDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentsDirectory.path, "test.db");
    var theDb = await openDatabase(path, version: 1, onCreate: _onCreate);
    return theDb;
  }

  void _onCreate(Database db, int version) async {
    // When creating the db, create the table
    await db.execute(
        "CREATE TABLE Employee(id INTEGER PRIMARY KEY, firstname TEXT, lastname TEXT, mobileno TEXT,emailId TEXT )");
    print("Created tables");
  }

  void saveEmployee(Employee employee) async {
    var dbClient = await db;
    await dbClient.transaction((txn) async {
      return await txn.rawInsert(
          'INSERT INTO Employee(firstname, lastname, mobileno, emailid ) VALUES(' +
              ''' +
              employee.firstName +
              ''' +
              ',' +
              ''' +
              employee.lastName +
              ''' +
              ',' +
              ''' +
              employee.mobileNo +
              ''' +
              ',' +
              ''' +
              employee.emailId +
              ''' +
              ')');
    });
  }

  Future<List<Employee>> getEmployees() async {
    var dbClient = await db;
    List<Map> list = await dbClient.rawQuery('SELECT * FROM Employee');
    List<Employee> employees = new List();
    for (int i = 0; i < list.length; i++) {
      employees.add(new Employee(list[i]["firstname"], list[i]["lastname"], list[i]["mobileno"], list[i]["emailid"]));
    }
    print(employees.length);
    return employees;
  }
}

(d). emloyeelist.dart

In this file a list of employees will be asynchronously fetched and rendered in a listview:

import 'package:flutter/material.dart';
import 'package:flutter_crud/model/employee.dart';
import 'dart:async';
import 'package:flutter_crud/database/dbhelper.dart';

Future<List<Employee>> fetchEmployeesFromDatabase() async {
  var dbHelper = DBHelper();
  Future<List<Employee>> employees = dbHelper.getEmployees();
  return employees;
}

class MyEmployeeList extends StatefulWidget {
  @override
  MyEmployeeListPageState createState() => new MyEmployeeListPageState();
}

class MyEmployeeListPageState extends State<MyEmployeeList> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Employee List'),
      ),
      body: new Container(
        padding: new EdgeInsets.all(16.0),
        child: new FutureBuilder<List<Employee>>(
          future: fetchEmployeesFromDatabase(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return new ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (context, index) {
                    return new Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          new Text(snapshot.data[index].firstName,
                              style: new TextStyle(
                                  fontWeight: FontWeight.bold, fontSize: 18.0)),
                          new Text(snapshot.data[index].lastName,
                              style: new TextStyle(
                                  fontWeight: FontWeight.bold, fontSize: 14.0)),
                          new Divider()
                        ]);
                  });
            } else if (snapshot.hasError) {
              return new Text("${snapshot.error}");
            }
            return new Container(alignment: AlignmentDirectional.center,child: new CircularProgressIndicator(),);
          },
        ),
      ),
    );
  }
}

(e). main.dart

The main class, where we define our main method, the entrypoint to our dart application:

import 'package:flutter/material.dart';
import 'package:flutter_crud/database/dbhelper.dart';
import 'package:flutter_crud/model/employee.dart';
import 'package:flutter_crud/employeelist.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'SQFLite DataBase Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

Employee employee = new Employee("", "", "", "");

String firstname;
String lastname;
String emailId;
String mobileno;
final scaffoldKey = new GlobalKey<ScaffoldState>();
final formKey = new GlobalKey<FormState>();

    @override
  Widget build(BuildContext context) {
    return new Scaffold(
      key: scaffoldKey,
      appBar: new AppBar(
        title: new Text('Saving Employee'),
        actions: <Widget>[
            new IconButton(
              icon: const Icon(Icons.view_list),
              tooltip: 'Next choice',
              onPressed: () {
              navigateToEmployeeList();
              },
            ),
          ]
      ),
      body: new Padding(
        padding: const EdgeInsets.all(16.0),
        child: new Form(
          key: formKey,
          child: new Column(
            children: [
              new TextFormField(
                keyboardType: TextInputType.text,
                decoration: new InputDecoration(labelText: 'First Name'),
                validator: (val) =>
                    val.length == 0 ?"Enter FirstName" : null,
                onSaved: (val) => this.firstname = val,
              ),
              new TextFormField(
                keyboardType: TextInputType.text,
                decoration: new InputDecoration(labelText: 'Last Name'),
                validator: (val) =>
                    val.length ==0 ? 'Enter LastName' : null,
                onSaved: (val) => this.lastname = val,
              ),
              new TextFormField(
                keyboardType: TextInputType.phone,
                decoration: new InputDecoration(labelText: 'Mobile No'),
                validator: (val) =>
                    val.length ==0 ? 'Enter Mobile No' : null,
                onSaved: (val) => this.mobileno = val,
              ),
              new TextFormField(
                keyboardType: TextInputType.emailAddress,
                decoration: new InputDecoration(labelText: 'Email Id'),
                validator: (val) =>
                    val.length ==0 ? 'Enter Email Id' : null,
                onSaved: (val) => this.emailId = val,
              ),
              new Container(margin: const EdgeInsets.only(top: 10.0),child: new RaisedButton(onPressed: _submit,
                child: new Text('Save Employee'),),)

            ],
          ),
        ),
      ),
    );
  }
  void _submit() {
     if (this.formKey.currentState.validate()) {
      formKey.currentState.save();
     }else{
       return null;
     }
    var employee = Employee(firstname,lastname,mobileno,emailId);
    var dbHelper = DBHelper();
    dbHelper.saveEmployee(employee);
    _showSnackBar("Data saved successfully");
  }

  void _showSnackBar(String text) {
    scaffoldKey.currentState
        .showSnackBar(new SnackBar(content: new Text(text)));
  }

  void navigateToEmployeeList(){
     Navigator.push(
    context,
    new MaterialPageRoute(builder: (context) => new MyEmployeeList()),
  );
  }
}

Download

Let's go over and download the project, or browse it from github.

No. Location Link
1. GitHub Direct Download
2. GitHub Browse

Credit and Thanks to the Original Creator of the above project @payen83

How to Run

  1. Download the project above.
  2. Create your application in android studio/visual studio as normal.
  3. Edit the pubspec.yaml to add the appopriate dependencies.
  4. Copy paste the dart files above into your project.

Then:

Just make sure you device or emulator is running and click the run button in android studio, it will automatically pick the device and install the app.

Aletrnative you can use the terminal or command prompt. Navigate/Cd over to project root page and type this:

flutter.bat build apk

This will build the APK which you can then drag and install onto your device. The build process in my machine takes around three minutes which is not bad.

Example 2: Flutter ToDo Notes App with SQflite

This is yet another simple and easy to understand SQFlite sample project. It is a todo app that utilizes the SQFlite to store todo items.

Here are the features of this app, what this app will teach you:

  • Add new note
  • Update note
  • Delete note
  • list all notes

Here are the demo screenshots:

Let's get started.

Step 1: Create Project

Create a flutter project in whatever editor or IDE you prefer.

Step 2: Dependencies

Navigate over to the pubspec.yaml and add the following dependencies:

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.0
  sqflite: ^1.3.2+1
  path_provider: ^1.3.0
  intl: ^0.16.1

Our most important is the sqflite as it is what will allow us save our items in the local sqlite database.

Step 3: Create Model class

The model class will represent a single ToDo Item. Each todo will have the following fields:

  • ID - the unique id of the todo item
  • NAME - the name of the todo item
  • Date - The date the todo item was created.

Here is our model class

TodoItem.dart

import 'package:flutter/material.dart';

class TodoItem extends StatelessWidget {
  int _id;
  String _itemName;
  String _dateCreated;

  TodoItem(this._itemName, this._dateCreated);

  TodoItem.map(dynamic obj) {
    this._itemName = obj['item_name'];
    this._dateCreated = obj['date_created'];
    this._id = obj['id'];
  }

  int get id => _id;

  String get itemName => _itemName;

  String get dateCreated => _dateCreated;

  Map<String, dynamic> toMap() {
    var map = Map<String, dynamic>();
    map['item_name'] = this._itemName;
    map['date_created'] = this._dateCreated;

    if (this._id != null) {
      map['id'] = this._id;
    }
    return map;
  }

  TodoItem.fromMap(Map<String, dynamic> map) {
    this._id = map['id'];
    this._itemName = map['item_name'];
    this._dateCreated = map['date_created'];
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.only(left: 16, right: 16, top: 8, bottom: 8),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text(
            _itemName,
            style: TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.bold,
                fontSize: 16.9),
          ),
          Padding(
            padding: const EdgeInsets.only(top : 8.0),
            child: Text(
              _dateCreated,
              style: TextStyle(
                color: Colors.white,
                fontSize: 12.5,
                fontStyle: FontStyle.italic,
              ),
            ),
          )
        ],
      ),
    );
  }
}

Step 4: Create Utility classes

Next we come and create our utility classes. We will have two such files:

DatabaseHelper.dart

This is where we will write our CRUD functions for working with SQLite database using SQFlite.

For example, the following function will initialize and open our database:

  initDb() async{
    Directory documentDirectory = await getApplicationDocumentsDirectory();
    String path = documentDirectory.path + "todo_db.db";

    var db = await openDatabase(path, version:  1, onCreate: _onCreate);
    return db;
  }

Here is how we create our database table;

  FutureOr<void> _onCreate(Database db, int version) async{
    await db.execute(
      "CREATE TABLE $tableItem ($columnId INTEGER PRIMARY KEY, $columnItemName TEXT, $columnDateCreated TEXT)"
    );
  }

And here is how insert into or save into our database:

  Future<int> saveItem(TodoItem item) async{
      var dbClient = await db;
      int res = await dbClient.insert('$tableItem', item.toMap());
      return res;
  }

Here is how retrieve a single item from our database;

  Future<TodoItem> getItem(int id) async {
      var dbClient = await db;
      var result = await dbClient.rawQuery('SELECT * FROM $tableItem WHERE $columnId = $id');
      return TodoItem.fromMap(result.first);
  }

Here is how we fetchall items from our SQLite database using SQFlite:

  Future<List> getAllItems() async {
      var dbClient = await db;
      var result = await dbClient.rawQuery('SELECT * FROM $tableItem ORDER BY $columnId DESC');
      return result.toList();
  }

Here is how we count the items in the database:

  Future<int> getItemsCount() async {
      var dbClient = await db;
      return Sqflite.firstIntValue(
        await dbClient.rawQuery('SELECT COUNT(*) FROM $tableItem')
      );
  }

Here is how delete an item from our database:

  Future<int> deleteItem(int id) async{
      var dbClient = await db;
      return await dbClient.delete(tableItem, where: "$columnId = ?", whereArgs: [id]);
  }

Here is how we update an existing item in our database:

  Future<int> updateItem(TodoItem item) async {
      var dbClient = await db;
      return await dbClient.update(tableItem, item.toMap(), where: '$columnId = ?', whereArgs: [item.id]);
  }

And here is we close our database:

  Future close() async {
    var dbClient = await db;
    return dbClient.close();
  }

Here is the full code:

import 'dart:async';
import 'dart:io';
import '../model/TodoItem.dart';

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

class DatabaseHelper {
  static DatabaseHelper _instance = DatabaseHelper._internal();
  static Database _db;

  final String tableItem = "items";
  final String columnId = "id";
  final String columnItemName= "item_name";
  final String columnDateCreated = "date_created";

  factory DatabaseHelper() {
    if (_instance == null) {
      _instance = DatabaseHelper._internal();
    }
    return _instance;
  }

  DatabaseHelper._internal();

  Future<Database> get db async {
    if (_db != null) {
      return _db;
    }

    _db = await initDb();
    return _db;
  }

  initDb() async{
    Directory documentDirectory = await getApplicationDocumentsDirectory();
    String path = documentDirectory.path + "todo_db.db";

    var db = await openDatabase(path, version:  1, onCreate: _onCreate);
    return db;
  }

  FutureOr<void> _onCreate(Database db, int version) async{
    await db.execute(
      "CREATE TABLE $tableItem ($columnId INTEGER PRIMARY KEY, $columnItemName TEXT, $columnDateCreated TEXT)"
    );
  }

  Future<int> saveItem(TodoItem item) async{
      var dbClient = await db;
      int res = await dbClient.insert('$tableItem', item.toMap());
      return res;
  }

  Future<TodoItem> getItem(int id) async {
      var dbClient = await db;
      var result = await dbClient.rawQuery('SELECT * FROM $tableItem WHERE $columnId = $id');
      return TodoItem.fromMap(result.first);
  }

  Future<List> getAllItems() async {
      var dbClient = await db;
      var result = await dbClient.rawQuery('SELECT * FROM $tableItem ORDER BY $columnId DESC');
      return result.toList();
  }

  Future<int> getItemsCount() async {
      var dbClient = await db;
      return Sqflite.firstIntValue(
        await dbClient.rawQuery('SELECT COUNT(*) FROM $tableItem')
      );
  }

  Future<int> deleteItem(int id) async{
      var dbClient = await db;
      return await dbClient.delete(tableItem, where: "$columnId = ?", whereArgs: [id]);
  }

  Future<int> updateItem(TodoItem item) async {
      var dbClient = await db;
      return await dbClient.update(tableItem, item.toMap(), where: '$columnId = ?', whereArgs: [item.id]);
  }

  Future close() async {
    var dbClient = await db;
    return dbClient.close();
  }

}

date_formatter.dart

This will format date. Here is the full code:

import 'package:intl/intl.dart';

String dateFormatted() {
        var date = DateTime.now();
        var formatter = DateFormat("EEE, MMM d, ''yy");
        String formattedDate = formatter.format(date);
        return formattedDate;
}

Step 5: Create UI Widgets

There are two widgets in this case:

(a). Home.dart

This will represent the Home screen:

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

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Todo App'),
        backgroundColor: Colors.indigoAccent,
      ),
      body: TodoScreen(),
    );
  }
}

TodoScreen.dart

This will construct the dialog used to enter and edit todo items. Here is the full code:

import 'package:flutter/material.dart';
import 'package:todo_app/util/DatabaseHelper.dart';
import '../model/TodoItem.dart';
import 'package:todo_app/util/date_formatter.dart';

class TodoScreen extends StatefulWidget {
  @override
  _TodoScreenState createState() => _TodoScreenState();
}

class _TodoScreenState extends State<TodoScreen> {
  final TextEditingController _textEditingController = TextEditingController();
  var dbHelper = DatabaseHelper();
  List<TodoItem> _itemsList = List<TodoItem>();

  @override
  void initState() {
    super.initState();
    _readTodoItemsList();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          Flexible(
            child: ListView.builder(
              itemBuilder: (_, int position) {
                return Card(
                  color: Colors.brown,
                  child: ListTile(
                    title: _itemsList[position],
                    onTap: () => _updateTodoItemDialog(_itemsList[position], position),
                    trailing: Listener(
                      key: Key(_itemsList[position].itemName),
                      child: Icon(
                        Icons.delete,
                        color: Colors.redAccent,
                      ),
                      onPointerDown: (pointerEvent) => _deleteTodoItem(_itemsList[position].id, position)
                      ,
                    ),
                  ),
                );
              },
              padding: EdgeInsets.all(8.0),
              reverse: false,
              itemCount: _itemsList.length,
            ),
          )
        ],
      ),
      backgroundColor: Colors.white10,
      floatingActionButton: FloatingActionButton(
        onPressed: _showFormDialog,
        child: Icon(Icons.add),
        backgroundColor: Colors.redAccent,
        tooltip: 'Tap to add item',
      ),
    );
  }

  void _showFormDialog() {
    var alert = AlertDialog(
      content: Row(
        children: <Widget>[
          Expanded(
              child: TextField(
            controller: _textEditingController,
            decoration: InputDecoration(
                labelText: 'Item',
                hintText: 'Add new item',
                icon: Icon(Icons.note_add)),
          ))
        ],
      ),
      actions: <Widget>[
        FlatButton(
            onPressed: () {
              _handleSubmit(_textEditingController.text);
              _textEditingController.clear();
              Navigator.pop(context);
            },
            child: Text('Add')),
        FlatButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Cancel'),
        )
      ],
    );
    showDialog(
        context: context,
        builder: (_) {
          return alert;
        });
  }

  _handleSubmit(String text) async {
    _textEditingController.clear();
    var item = TodoItem(text, dateFormatted());
    int savedItemId = await dbHelper.saveItem(item);
    var addedItem = await dbHelper.getItem(savedItemId);
    setState(() {
      _itemsList.insert(0, addedItem);
    });
  }

  _readTodoItemsList() async {
    var items = await dbHelper.getAllItems();
    print('List $_itemsList');
    items.forEach((item) {
      setState(() {
        var todoItem = TodoItem.fromMap(item);
        _itemsList.add(todoItem);
      });
    });
  }

  _deleteTodoItem(int id, int position) async{
    await dbHelper.deleteItem(id);

    setState(() {
      _itemsList.removeAt(position);
    });

  }

  _updateTodoItemDialog(TodoItem item, int position) {

    var alert = AlertDialog(
      title: Text(
        'Update Item'
      ),
      content: Row(
        children: <Widget>[
          Expanded(
            child: TextField(
              controller: _textEditingController,
              decoration: InputDecoration(
                labelText: 'Item',
                icon: Icon(Icons.update)
              ),
            ),
          )
        ],
      ),
      actions: <Widget>[
        FlatButton(onPressed: () async{
          TodoItem updatedItem = TodoItem.fromMap({
            'item_name' : _textEditingController.text,
            'date_created' : dateFormatted(),
            'id' : item.id
          });

          _handleSubmittedUpdate(position, item);
          await dbHelper.updateItem(updatedItem);
          setState(() {
            _readTodoItemsList();
          });
          Navigator.pop(context);

        }, child: Text(
          'Update'
        )),
        FlatButton(onPressed: () => Navigator.pop(context), child: Text(
          'Cancel'
        ))
      ],

    );
    showDialog(context: context, builder: (_) {
      return alert;
    });

  }

  void _handleSubmittedUpdate(int position, TodoItem item) {
    _itemsList.removeWhere((element) => _itemsList[position].id == item.id);
  }
}

Step 6: Create Main class

Our main class will be a stateless widget known as MyApp. Here is the full code:

main.dart

import 'package:flutter/material.dart';
import 'ui/Home.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      home: Home(),
    );
  }
}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

Number Link
1. Download Example
2. Follow code author