SQLite is a very popular choice of local storage database. It is an SQL lightweight and serverless SQL database engine that is highly efficient and user-friendly. Flutter, Google's UI toolkit for building natively compiled applications, doesn't come with built-in support for local data storage but provides robust support for integrating SQLite databases. Therefore, SQLite can be easily integrated into Flutter projects to store and retrieve structured data locally.
In this article, we will get to know how we can integrate and use the SQLite database with the Flutter project, Stepwise with an example of the user management database of GeeksforGeeks.
Prerequisites
Before we dive in, there are a few things you'll need to have:
- Basic knowledge of Flutter and Dart
- Flutter SDK installed
- Dart SDK installed
- IDEs such as VSCode & Android Studio
Having these prerequisites in place will set you up for success as we move forward. So, make sure you have them ready before we get started.
Steps to Integrate SQLite Database in Flutter
Step 1: Create a new Flutter Application
Create a new Flutter application using the command Prompt. To create a new app, write the following command and run it.
flutter create app_name
To know more about it refer this article: Creating a Simple Application in Flutter
Step 2: Adding Dependencies
To get started, open up your pubsec.yaml file in the project structure. Now, you'll want to add the following dependencies:
dependencies:
flutter:
sdk: flutter
sqflite: ^2.4.2
- sqflite is the package that provides SQLite integration for Flutter.
Now, run the command below in the terminal.
flutter pub get
Or
Run the below command in the terminal.
flutter pub add sqflite
Step 3: Defining the User Model
Create a file in the 'lib/user.dart' to define a model class to represent user data. Here's an example of a simple gfg user model class that has a user ID, a username, and an email, along with a constructor that initializes the data members :
user.dart
class User {
final int? id;
final String username;
final String email;
User({this.id, required this.username, required this.email});
Map<String, dynamic> toMap() {
return {'id': id, 'username': username, 'email': email};
}
factory User.fromMap(Map<String, dynamic> map) {
return User(
id: map['id'],
username: map['username'],
email: map['email'],
);
}
}
Step 4: Defining the Database Class
In the Database helper class, we have all the functions implemented here, The Database class has the following methods
- initDb(): The function is used to initialize the database. It checks if the 'gfg_users' table exists, and if it doesn't, it creates it.
- _onCreate(): It is a callback function that gets executed when the database is created. Its purpose is to define the schema of the 'users' table.
- insertUser(): To insert a new user into the 'gfg_users' table.
- queryAllUsers(): Retrieves all users from the 'gfg_users' table.
- updateUser(): To update an existing user in the 'gfg_users' table.
- deleteUser(): Deletes a user from the 'gfg_users' table by their ID.
database_helper.dart
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'user.dart';
class DatabaseHelper {
static final DatabaseHelper instance = DatabaseHelper._instance();
static Database? _database;
DatabaseHelper._instance();
Future<Database> get db async {
_database ??= await initDb();
return _database!;
}
Future<Database> initDb() async {
String databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'geeksforgeeks.db');
return await openDatabase(path, version: 1, onCreate: _onCreate);
}
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE gfg_users (
id INTEGER PRIMARY KEY,
username TEXT,
email TEXT
)
''');
}
Future<int> insertUser(User user) async {
Database db = await instance.db;
return await db.insert('gfg_users', user.toMap());
}
Future<List<Map<String, dynamic>>> queryAllUsers() async {
Database db = await instance.db;
return await db.query('gfg_users');
}
Future<int> updateUser(User user) async {
Database db = await instance.db;
return await db.update('gfg_users', user.toMap(), where: 'id = ?', whereArgs: [user.id]);
}
Future<int> deleteUser(int id) async {
Database db = await instance.db;
return await db.delete('gfg_users', where: 'id = ?', whereArgs: [id]);
}
Future<void> initializeUsers() async {
List<User> usersToAdd = [
User(username: 'John', email: '[email protected]'),
User(username: 'Jane', email: '[email protected]'),
User(username: 'Alice', email: '[email protected]'),
User(username: 'Bob', email: '[email protected]'),
];
for (User user in usersToAdd) {
await insertUser(user);
}
}
}
Step 5: Defining the main file
- Initialization: We make sure to initialize the database and insert the users before running the MyApp widget.
- User List Display: The UserList widget is responsible for displaying the list of users that we fetch from the database using the DatabaseHelper class.
- State Management: To keep things organized, we use the initState method to fetch the users when the widget is first initialized and update the user interface accordingly.
- User Display: We show each user's username and email using a ListTile widget within a ListView.builder.
main.dart
import 'package:flutter/material.dart';
import 'database_helper.dart'; // Import the DatabaseHelper class
import 'user.dart'; // Import the User class
void main() async {
// Initialize the database and insert users
WidgetsFlutterBinding.ensureInitialized();
await DatabaseHelper.instance.initDb();
await DatabaseHelper.instance.initializeUsers();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'User Management',
home: UserList(),
);
}
}
class UserList extends StatefulWidget {
@override
_UserListState createState() => _UserListState();
}
class _UserListState extends State<UserList> {
List<User> _users = [];
@override
void initState() {
super.initState();
_fetchUsers();
}
Future<void> _fetchUsers() async {
final userMaps = await DatabaseHelper.instance.queryAllUsers();
setState(() {
_users = userMaps.map((userMap) => User.fromMap(userMap)).toList();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('GFG User List'),
backgroundColor: Colors.lightGreen,
),
body: ListView.builder(
itemCount: _users.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(_users[index].username),
subtitle: Text(_users[index].email),
);
},
),
);
}
}
Output:
Thus, by following these steps, we can integrate SQLite in a Flutter project.