MENU
カテゴリー
\気になるカテゴリーをクリック!/
MENU
\気になるカテゴリーをクリック!/
Flutterでローカルデータベースの使い方法を知りたい
FlutterでSQLiteの使い方を知りたい。
そこで、今回はFlutterでSQLiteにおける基本的な使い方をサンプルコードとデモアプリで解説します。
不明点などありましたら、お気軽にお問い合わせ下さい。
フリーランスのFlutterエンジニアとして働きたい方にオススメのエージェントはこちらで詳しく解説しています。
SQLiteはDBサーバーへのアクセスなしで管理できるローカルDB。SQLiteは全てのスマホで使われて、世界で1番利用されるDBです。
SQLiteとは
サーバとしてではなくアプリケーションに組み込んで利用されるデータベース。 一般的なRDBMSと違い、APIは単純にライブラリを呼び出すだけであり、データの保存に単一のファイルのみを使用することが特徴である。
引用:SQLite公式サイト
SQLiteの使い方とデモアプリのサンプルコードを解説します!
下のデモ動画では、各ボタンをクリックするとデータの登録、照会、更新、削除がされ、コンソールに処理結果を表示するシンプルな作りです。
SQLiteの実装手順は以下の通りです。
デモアプリで利用するライブラリ/パッケージ(SQLite以外)
ライブラリ | 内容 |
---|---|
dart:io | Dart言語で使用できる I/O (Input/Output) ライブラリ。このライブラリを使用すると、Dart のアプリケーションからファイルやネットワークを操作することができます。 |
path | Dart のコアライブラリに含まれているもので、ファイルやディレクトリのパスを扱うためのユーティリティ関数を提供。 例)ファイルやディレクトリのパスを操作(パスの結合・分解・拡張子を取得など) ファイルやディレクトリの名前を操作(ファイル名取得、ディレクトリ名取得など) |
path_provider | アプリがデータを保存するためのパスや、デバイスの一般的なパスを取得することができる。 |
デモアプリのファイル構成
main.dartファイルと、database_helperファイルに実装します。database_helperファイルにDB接続やデータ更新処理などを記述します。
SQLiteのプラグインsqfliteをpubspec.yamlファイルに定義します。
dependencies:
flutter:
sdk: flutter
sqflite: ^2.2.0+3
path_provider: ^2.0.11
sqfliteをインポートする。
import 'package:sqflite/sqflite.dart';
データベースのデータを保存するディレクトリパスの取得から、データベース接続・初期化、テーブル作成をします。
各処理にコメントをつけておりますので、処理内容の詳細はそちらからご確認ください。
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
class DatabaseHelper {
static final _databaseName = "MyDatabase.db"; // DB名
static final _databaseVersion = 1; // スキーマのバージョン指定
static final table = 'my_table'; // テーブル名
static final columnId = '_id'; // カラム名:ID
static final columnName = 'name'; // カラム名:Name
static final columnAge = 'age'; // カラム名:age
// DatabaseHelper クラスを定義
DatabaseHelper._privateConstructor();
// DatabaseHelper._privateConstructor() コンストラクタを使用して生成されたインスタンスを返すように定義
// DatabaseHelper クラスのインスタンスは、常に同じものであるという保証
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
// Databaseクラス型のstatic変数_databaseを宣言
// クラスはインスタンス化しない
static Database? _database;
// databaseメソッド定義
// 非同期処理
Future<Database?> get database async {
// _databaseがNULLか判定
// NULLの場合、_initDatabaseを呼び出しデータベースの初期化し、_databaseに返す
// NULLでない場合、そのまま_database変数を返す
// これにより、データベースを初期化する処理は、最初にデータベースを参照するときにのみ実行されるようになります。
// このような実装を「遅延初期化 (lazy initialization)」と呼びます。
if (_database != null) return _database;
_database = await _initDatabase();
return _database;
}
// データベース接続
_initDatabase() async {
// アプリケーションのドキュメントディレクトリのパスを取得
Directory documentsDirectory = await getApplicationDocumentsDirectory();
// 取得パスを基に、データベースのパスを生成
String path = join(documentsDirectory.path, _databaseName);
// データベース接続
return await openDatabase(path,
version: _databaseVersion,
// テーブル作成メソッドの呼び出し
onCreate: _onCreate);
}
// テーブル作成
// 引数:dbの名前
// 引数:スキーマーのversion
// スキーマーのバージョンはテーブル変更時にバージョンを上げる(テーブル・カラム追加・変更・削除など)
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $table (
$columnId INTEGER PRIMARY KEY,
$columnName TEXT NOT NULL,
$columnAge INTEGER NOT NULL
)
''');
}
データ登録処理のサンプルコードは以下の通りです。main.dartファイルの処理からdatabase_helper.dartファイルの処理を呼び出してデータの登録を行います。
insert
メソッドは、非同期で実行され、データベースにレコード追加処理をして、追加レコードの ID を返します。
void _insert() async {
Map<String, dynamic> row = {
DatabaseHelper.columnName : '山田 太郎',
DatabaseHelper.columnAge : 35
};
final id = await dbHelper.insert(row);
print('登録しました。id: $id');
}
insert
メソッドは、非同期で実行され、データベースにレコード追加処理をして、追加レコードの ID を返します。
Future<int> insert(Map<String, dynamic> row) async {
Database? db = await instance.database;
return await db!.insert(table, row);
}
データ照会処理のサンプルコードは以下の通りです。main.dartファイルの処理からdatabase_helper.dartファイルの処理を呼び出してデータの照会を行います。
// 照会ボタンクリック
void _query() async {
final allRows = await dbHelper.queryAllRows();
print('全てのデータを照会しました。');
allRows.forEach(print);
}
Future<List<Map<String, dynamic>>> queryAllRows() async {
Database? db = await instance.database;
return await db!.query(table);
}
データ更新処理のサンプルコードは以下の通りです。main.dartファイルの処理からdatabase_helper.dartファイルの処理を呼び出してデータの更新を行います。
// 更新ボタンクリック
void _update() async {
Map<String, dynamic> row = {
DatabaseHelper.columnId : 1,
DatabaseHelper.columnName : '鈴木 一郎',
DatabaseHelper.columnAge : 48
};
final rowsAffected = await dbHelper.update(row);
print('更新しました。 ID:$rowsAffected ');
}
Future<int> update(Map<String, dynamic> row) async {
Database? db = await instance.database;
int id = row[columnId];
return await db!.update(table, row, where: '$columnId = ?', whereArgs: [id]);
}
データ削除処理のサンプルコードは以下の通りです。main.dartファイルの処理からdatabase_helper.dartファイルの処理を呼び出してデータの削除を行います。
// 削除ボタンクリック
void _delete() async {
final id = await dbHelper.queryRowCount();
final rowsDeleted = await dbHelper.delete(id!);
print('削除しました。 $rowsDeleted ID: $id');
}
// レコード数を確認
Future<int?> queryRowCount() async {
Database? db = await instance.database;
return Sqflite.firstIntValue(await db!.rawQuery('SELECT COUNT(*) FROM $table'));
}
Future<int> delete(int id) async {
Database? db = await instance.database;
return await db!.delete(table, where: '$columnId = ?', whereArgs: [id]);
}
デモ動画画面のソースコードは以下の通りです。
import 'package:flutter/material.dart';
import 'database_helper.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
// DatabaseHelper クラスのインスタンス取得
final dbHelper = DatabaseHelper.instance;
// homepage layout
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SQLiteデモ'),
),
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
ElevatedButton(
child: Text('登録', style: TextStyle(fontSize: 35),),
onPressed: _insert,
),
ElevatedButton(
child: Text('照会', style: TextStyle(fontSize: 35),),
onPressed: _query,
),
ElevatedButton(
child: Text('更新', style: TextStyle(fontSize: 35),),
onPressed: _update,
),
ElevatedButton(
child: Text('削除', style: TextStyle(fontSize: 35),),
onPressed: _delete,
),
],
),
),
);
}
// 登録ボタンクリック
void _insert() async {
// row to insert
Map<String, dynamic> row = {
DatabaseHelper.columnName : '山田 太郎',
DatabaseHelper.columnAge : 35
};
final id = await dbHelper.insert(row);
print('登録しました。id: $id');
}
// 照会ボタンクリック
void _query() async {
final allRows = await dbHelper.queryAllRows();
print('全てのデータを照会しました。');
allRows.forEach(print);
}
// 更新ボタンクリック
void _update() async {
Map<String, dynamic> row = {
DatabaseHelper.columnId : 1,
DatabaseHelper.columnName : '鈴木 一郎',
DatabaseHelper.columnAge : 48
};
final rowsAffected = await dbHelper.update(row);
print('更新しました。 ID:$rowsAffected ');
}
// 削除ボタンクリック
void _delete() async {
final id = await dbHelper.queryRowCount();
final rowsDeleted = await dbHelper.delete(id!);
print('削除しました。 $rowsDeleted ID: $id');
}
}
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
class DatabaseHelper {
static final _databaseName = "MyDatabase.db"; // DB名
static final _databaseVersion = 1; // スキーマのバージョン指定
static final table = 'my_table'; // テーブル名
static final columnId = '_id'; // カラム名:ID
static final columnName = 'name'; // カラム名:Name
static final columnAge = 'age'; // カラム名:age
// DatabaseHelper クラスを定義
DatabaseHelper._privateConstructor();
// DatabaseHelper._privateConstructor() コンストラクタを使用して生成されたインスタンスを返すように定義
// DatabaseHelper クラスのインスタンスは、常に同じものであるという保証
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
// Databaseクラス型のstatic変数_databaseを宣言
// クラスはインスタンス化しない
static Database? _database;
// databaseメソッド定義
// 非同期処理
Future<Database?> get database async {
// _databaseがNULLか判定
// NULLの場合、_initDatabaseを呼び出しデータベースの初期化し、_databaseに返す
// NULLでない場合、そのまま_database変数を返す
// これにより、データベースを初期化する処理は、最初にデータベースを参照するときにのみ実行されるようになります。
// このような実装を「遅延初期化 (lazy initialization)」と呼びます。
if (_database != null) return _database;
_database = await _initDatabase();
return _database;
}
// データベース接続
_initDatabase() async {
// アプリケーションのドキュメントディレクトリのパスを取得
Directory documentsDirectory = await getApplicationDocumentsDirectory();
// 取得パスを基に、データベースのパスを生成
String path = join(documentsDirectory.path, _databaseName);
// データベース接続
return await openDatabase(path,
version: _databaseVersion,
// テーブル作成メソッドの呼び出し
onCreate: _onCreate);
}
// テーブル作成
// 引数:dbの名前
// 引数:スキーマーのversion
// スキーマーのバージョンはテーブル変更時にバージョンを上げる(テーブル・カラム追加・変更・削除など)
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $table (
$columnId INTEGER PRIMARY KEY,
$columnName TEXT NOT NULL,
$columnAge INTEGER NOT NULL
)
''');
}
// 登録処理
Future<int> insert(Map<String, dynamic> row) async {
Database? db = await instance.database;
return await db!.insert(table, row);
}
// 照会処理
Future<List<Map<String, dynamic>>> queryAllRows() async {
Database? db = await instance.database;
return await db!.query(table);
}
// レコード数を確認
Future<int?> queryRowCount() async {
Database? db = await instance.database;
return Sqflite.firstIntValue(await db!.rawQuery('SELECT COUNT(*) FROM $table'));
}
// 更新処理
Future<int> update(Map<String, dynamic> row) async {
Database? db = await instance.database;
int id = row[columnId];
return await db!.update(table, row, where: '$columnId = ?', whereArgs: [id]);
}
// 削除処理
Future<int> delete(int id) async {
Database? db = await instance.database;
return await db!.delete(table, where: '$columnId = ?', whereArgs: [id]);
}
}
今回はFlutterのSQLiteにおける基本的な使い方をサンプルコードとデモ画面で解説しました。
オリジナルアプリ開発で、ローカルデータベースを利用したい方は是非押さえておきましょう!
より実践的なSQLiteを使ったアプリは、Udemyの
Flutter & Dart – The Complete Guide [2023 Edition]で学習できます。
Flutterエンジニアになるには?
初心者が中級者レベルのFlutterエンジニアなるまでの進め方をまとめました。
Flutterの学習方法を知る
Flutter をスクールで学ぶ
Flutterの副業を探す
おまけ:Flutter入門の完全ガイド
Flutter/Dartの基礎一覧
Flutter/Dartの入門知識として押さえておきたい内容をまとめました。学習のご参考にどうぞ。
Widget(ウィジェット) 一覧
Dart 基本文法
ライブラリ 使い方
コメント