Flutter 學習之旅 之 flutter 使用 SQLite(sqflite) 實現簡單的數據本地化 保存/獲取/移除/判斷是否存在 的簡單封裝
目錄
Flutter 學習之旅 之 flutter 使用 SQLite(sqflite) 實現簡單的數據本地化 保存/獲取/移除/判斷是否存在 的簡單封裝
一、簡單介紹
2. Path_provider
3. SQLite
二、sqflite
三、安裝 sqflite
四、簡單案例實現
五、關鍵代碼
一、簡單介紹
Flutter 是一款開源的 UI 軟件開發工具包,由 Google 開發和維護。它允許開發者使用一套代碼同時構建跨平臺的應用程序,包括移動設備(iOS 和 Android)、Web 和桌面平臺(Windows、macOS 和 Linux)。
Flutter 使用 Dart 編程語言,它可以將代碼編譯為 ARM 或 Intel 機器代碼以及 JavaScript,從而實現快速的性能。Flutter 提供了一個豐富的預置小部件庫,開發者可以根據自己的需求靈活地控制每個像素,從而創建自定義的、適應性強的設計,這些設計在任何屏幕上都能呈現出色的外觀和感覺。
在Flutter中,進行本地化保存的方法主要有以下幾種:
1. SharedPreferences
SharedPreferences
是一種輕量級的存儲方案,適用于存儲簡單的鍵值對數據,如字符串、整數、布爾值等。它類似于Android中的
SharedPreferences
或iOS中的UserDefaults
,使用起來非常方便。
優點:簡單易用,適合存儲少量數據。
缺點:只能存儲基本數據類型,不適合存儲大量數據
。
2. Path_provider
path_provider
插件提供了一種平臺無關的方式,用于訪問設備的文件系統。它支持訪問兩種文件位置系統:
臨時文件夾:系統可以隨時清空的臨時(緩存)文件夾。
Documents目錄:供應用使用,只有在刪除應用時,系統才會清除這個目錄
。
通過
path_provider
,你可以將數據以文件的形式保存到本地,適合存儲一些持久化數據或從網絡下載的數據。
3. SQLite
SQLite
是一種輕量級的關系型數據庫,適用于存儲結構化的數據。它提供了強大的數據查詢和管理功能,適合存儲大量數據。
優點:功能強大,支持復雜的數據結構和查詢。
缺點:使用相對復雜,需要編寫SQL語句
。
二、sqflite
sqflite
是一個用于 Flutter 的 SQLite 數據庫插件,允許開發者在移動應用中存儲和管理本地數據。它提供了簡單易用的 API,支持創建數據庫、執行 SQL 查詢、插入、更新、刪除等操作。sqflite
基于 SQLite,適合存儲結構化數據,如用戶信息、設置等。它支持 Android 和 iOS 平臺,通過 Dart 語言操作,方便與 Flutter 應用集成。使用 sqflite
可以實現數據的持久化存儲,提升應用的性能和用戶體驗。
在開發和使用
sqflite
時,需要注意以下幾點以確保代碼的正確性和性能優化:1. 初始化數據庫
確保初始化:在使用
sqflite
之前,必須先初始化數據庫。通常在應用啟動時調用WidgetsFlutterBinding.ensureInitialized()
,然后初始化數據庫實例。數據庫路徑:使用
getDatabasesPath()
獲取數據庫存儲路徑,確保路徑正確。2. 數據庫版本管理
版本控制:通過
version
參數管理數據庫版本。如果需要更新數據庫結構,可以在onUpgrade
回調中編寫升級邏輯。兼容性:確保升級邏輯兼容舊版本數據,避免數據丟失。
3. 表結構設計
主鍵設計:合理設計表的主鍵,避免重復和沖突。例如,使用
INTEGER PRIMARY KEY AUTOINCREMENT
或TEXT PRIMARY KEY
。字段類型:選擇合適的字段類型,如
TEXT
、INTEGER
、REAL
和BLOB
,以優化存儲和查詢性能。4. 事務管理
使用事務:對于多個操作(如批量插入或更新),使用事務可以提高性能并確保數據一致性。
await db.transaction((txn) async {await txn.insert('table', data1);await txn.insert('table', data2); });
5. 查詢優化
索引:為經常查詢的字段創建索引,提高查詢效率。
await db.execute('CREATE INDEX idx_column ON table (column)');
避免全表掃描:盡量使用
WHERE
子句進行條件查詢,避免全表掃描。6. 錯誤處理
捕獲異常:在數據庫操作中捕獲異常,避免應用崩潰。
try {await db.insert('table', data); } catch (e) {print('Error: $e'); }
7. 資源管理
關閉數據庫:在應用退出或不再需要時關閉數據庫連接,釋放資源。
await db.close();
8. 異步操作
使用
await
:所有數據庫操作都是異步的,使用await
確保操作完成后再繼續執行。避免阻塞主線程:確保數據庫操作不會阻塞主線程,影響用戶體驗。
9. 測試
單元測試:編寫單元測試驗證數據庫操作的正確性。
模擬數據:在測試環境中使用模擬數據,避免依賴真實數據。
10. 安全性
SQL 注入:使用參數化查詢,避免 SQL 注入攻擊。
await db.query('table', where: 'column = ?', whereArgs: [value]);
11. 備份和恢復
備份數據:定期備份數據庫文件,防止數據丟失。
恢復數據:提供恢復機制,允許用戶從備份中恢復數據。
12. 日志和調試
啟用日志:在開發過程中啟用日志,方便調試。
await db.execute('PRAGMA journal_mode=WAL');
通過遵循這些注意事項,可以確保
sqflite
的使用更加高效、穩定和安全,提升應用的整體質量。
三、安裝 sqflite
1、直接運行命令:flutter pub add sqflite
2、或者在?pubspec.yaml 添加
dependencies:sqflite: ^2.4.2
四、簡單案例實現
1、這里使用 Android Studio 進行創建 Flutter 項目
2、創建一個 application 的 Flutter 項目
3、項目結構如下
?
4、編寫一個 DatabaseHelper
5、在 main 中編寫一個測試代碼
6、運行打印如下
7、繼續編寫一個復雜些的
8、在 main 中編寫一個測試代碼
9、運行打印如下
五、關鍵代碼
1、DatabaseHelper 一
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';class DatabaseHelper {// 數據庫文件名static const String dbName = "localization.db";// 數據庫版本號,用于版本控制和升級static const int dbVersion = 1;// 數據表名,用于存儲本地化數據static const String tableLocalization = "localization";// 數據表中的鍵字段名static const String columnKey = "key";// 數據表中的值字段名static const String columnValue = "value";// 私有數據庫實例變量,用于存儲數據庫連接Database? _database;// 獲取數據庫實例的公共方法// 如果數據庫已經初始化,則直接返回;否則初始化數據庫并返回Future<Database> get database async {if (_database != null) return _database!;_database = await _initDatabase();return _database!;}// 初始化數據庫的方法Future<Database> _initDatabase() async {// 獲取設備的數據庫存儲路徑String path = join(await getDatabasesPath(), dbName);// 打開或創建數據庫文件// 如果數據庫不存在,則會調用 onCreate 回調方法來創建表return await openDatabase(path, version: dbVersion, onCreate: _onCreate);}// 數據庫創建時調用的回調方法// 用于創建數據表結構Future<void> _onCreate(Database db, int version) async {// 執行 SQL 語句,創建 localization 表// 表包含兩個字段:key(主鍵,唯一)和 valueawait db.execute('''CREATE TABLE $tableLocalization ($columnKey TEXT PRIMARY KEY, // 鍵字段,作為主鍵$columnValue TEXT // 值字段)''');}// 保存本地化數據的方法Future<void> saveLocalization(String key, String value) async {// 獲取數據庫實例Database db = await database;// 插入數據到 localization 表// 如果 key 已存在,則使用 ConflictAlgorithm.replace 策略替換原有數據await db.insert(tableLocalization, {columnKey: key, columnValue: value},conflictAlgorithm: ConflictAlgorithm.replace);}// 獲取本地化數據的方法Future<String?> getLocalization(String key) async {// 獲取數據庫實例Database db = await database;// 查詢 localization 表,查找指定 key 的數據List<Map<String, dynamic>> result = await db.query(tableLocalization,where: '$columnKey = ?', whereArgs: [key]);// 如果查詢結果不為空,返回 value 字段的值;否則返回 nullreturn result.isNotEmpty ? result.first[columnValue] as String? : null;}// 移除本地化數據的方法Future<void> removeLocalization(String key) async {// 獲取數據庫實例Database db = await database;// 從 localization 表中刪除指定 key 的數據await db.delete(tableLocalization, where: '$columnKey = ?', whereArgs: [key]);}// 判斷是否存在指定 key 的本地化數據的方法Future<bool> hasLocalization(String key) async {// 獲取數據庫實例Database db = await database;// 查詢 localization 表,查找指定 key 的數據List<Map<String, dynamic>> result = await db.query(tableLocalization,where: '$columnKey = ?', whereArgs: [key]);// 如果查詢結果不為空,返回 true;否則返回 falsereturn result.isNotEmpty;}
}
代碼說明
常量定義:
dbName
:定義數據庫文件的名稱。
dbVersion
:定義數據庫的版本號,用于版本控制和升級。
tableLocalization
:定義存儲本地化數據的表名。
columnKey
和columnValue
:定義表中的字段名,分別用于存儲鍵和值。數據庫初始化:
_initDatabase
方法通過getDatabasesPath
獲取設備的數據庫存儲路徑,并使用openDatabase
打開或創建數據庫文件。如果數據庫文件不存在,則會調用
_onCreate
方法來創建表結構。表結構創建:
_onCreate
方法中,使用 SQL 語句創建localization
表,包含兩個字段:key
(主鍵,唯一)和value
。數據操作方法:
saveLocalization
:插入或更新數據到localization
表。
getLocalization
:查詢指定key
的數據,返回對應的value
。
removeLocalization
:刪除指定key
的數據。
hasLocalization
:判斷是否存在指定key
的數據。通過這些注釋,你可以更清晰地理解每個方法的作用和實現邏輯,便于在項目中使用和維護。
2、main 一
import 'package:flutter/material.dart'; // 導入 Flutter 的 Material 組件庫
import 'package:test_sqflite_0317/database_helper.dart'; // 導入封裝的 DatabaseHelper 類void main() async {// 確保 Flutter 綁定初始化// 在使用 Flutter 的異步操作(如數據庫操作)之前,需要調用此方法來初始化 Flutter 的綁定。// 這是 Flutter 應用程序啟動時的必要步驟,確保可以使用 Flutter 提供的異步功能。WidgetsFlutterBinding.ensureInitialized();// 創建 DatabaseHelper 的實例// DatabaseHelper 是一個封裝類,用于管理本地化數據的保存、獲取、移除等操作。var dbHelper = DatabaseHelper();// 保存數據到數據庫// 調用 DatabaseHelper 的 saveLocalization 方法,將鍵 'language' 和值 'en' 保存到數據庫中。// 這里的 'language' 是一個示例鍵,'en' 是對應的值,表示語言設置為英語。await dbHelper.saveLocalization('language', 'en');// 從數據庫中獲取保存的數據// 調用 DatabaseHelper 的 getLocalization 方法,通過鍵 'language' 獲取對應的值。// 如果數據庫中存在該鍵,則返回對應的值;否則返回 null。String? language = await dbHelper.getLocalization('language');// 打印獲取到的語言設置// 如果成功獲取到值,則打印 'Saved language: en';否則打印 'Saved language: null'。print('Saved language: $language');// 判斷數據庫中是否有保存的數據// 調用 DatabaseHelper 的 hasLocalization 方法,檢查鍵 'language' 是否存在于數據庫中。// 如果存在,返回 true;否則返回 false。bool hasLanguage = await dbHelper.hasLocalization('language');// 打印判斷結果// 如果存在該鍵,則打印 'Has language: true';否則打印 'Has language: false'。print('Has language: $hasLanguage');// 從數據庫中移除保存的數據// 調用 DatabaseHelper 的 removeLocalization 方法,通過鍵 'language' 刪除對應的記錄。await dbHelper.removeLocalization('language');// 再次判斷數據庫中是否有保存的數據// 再次調用 hasLocalization 方法,檢查鍵 'language' 是否還存在于數據庫中。hasLanguage = await dbHelper.hasLocalization('language');// 打印判斷結果// 由于已經刪除了該鍵,因此打印 'Has language after removal: false'。print('Has language after removal: $hasLanguage');
}
代碼說明
導入必要的庫:
flutter/material.dart
:導入 Flutter 的 Material 組件庫,用于構建 Flutter 應用。
test_sqflite_0317/database_helper.dart
:導入封裝的DatabaseHelper
類,該類提供了數據庫操作的接口。初始化 Flutter 綁定:
WidgetsFlutterBinding.ensureInitialized()
:在使用 Flutter 的異步操作之前,必須調用此方法來初始化 Flutter 的綁定。這是 Flutter 應用程序啟動時的必要步驟。創建
DatabaseHelper
實例:
var dbHelper = DatabaseHelper()
:創建DatabaseHelper
的實例,用于后續的數據庫操作。保存數據:
await dbHelper.saveLocalization('language', 'en')
:調用DatabaseHelper
的saveLocalization
方法,將鍵'language'
和值'en'
保存到數據庫中。獲取保存的數據:
String? language = await dbHelper.getLocalization('language')
:調用DatabaseHelper
的getLocalization
方法,通過鍵'language'
獲取對應的值。
print('Saved language: $language')
:打印獲取到的語言設置。判斷是否有保存的數據:
bool hasLanguage = await dbHelper.hasLocalization('language')
:調用DatabaseHelper
的hasLocalization
方法,檢查鍵'language'
是否存在于數據庫中。
print('Has language: $hasLanguage')
:打印判斷結果。移除保存的數據:
await dbHelper.removeLocalization('language')
:調用DatabaseHelper
的removeLocalization
方法,通過鍵'language'
刪除對應的記錄。再次判斷是否有保存的數據:
hasLanguage = await dbHelper.hasLocalization('language')
:再次調用hasLocalization
方法,檢查鍵'language'
是否還存在于數據庫中。
print('Has language after removal: $hasLanguage')
:打印判斷結果。通過這些注釋,你可以更清晰地理解代碼的邏輯和功能,便于在項目中使用和維護。
3、DatabaseHelper 二
import 'package:sqflite/sqflite.dart'; // 導入 sqflite 包,用于操作 SQLite 數據庫
import 'package:path/path.dart'; // 導入 path 包,用于處理文件路徑class DatabaseHelper {// 數據庫文件名static const String dbName = "user_management.db";// 數據庫版本號,用于版本控制和升級static const int dbVersion = 1;// 數據表名,用于存儲用戶信息static const String tableUsers = "users";// 數據表中的用戶ID字段名,主鍵static const String columnId = "id";// 數據表中的用戶姓名字段名static const String columnName = "name";// 數據表中的用戶郵箱字段名,唯一約束static const String columnEmail = "email";// 私有數據庫實例變量,用于存儲數據庫連接Database? _database;// 獲取數據庫實例的公共方法// 如果數據庫已經初始化,則直接返回;否則初始化數據庫并返回Future<Database> get database async {if (_database != null) return _database!;_database = await _initDatabase();return _database!;}// 初始化數據庫的方法// 獲取數據庫存儲路徑,并打開或創建數據庫文件Future<Database> _initDatabase() async {// 使用 getDatabasesPath 獲取設備的數據庫存儲路徑String path = join(await getDatabasesPath(), dbName);// 打開或創建數據庫文件,指定版本號和 onCreate 回調方法return await openDatabase(path, version: dbVersion, onCreate: _onCreate);}// 數據庫創建時調用的回調方法// 用于創建數據表結構Future<void> _onCreate(Database db, int version) async {// 執行 SQL 語句,創建 users 表// 表包含三個字段:id(自增主鍵)、name(非空)、email(非空且唯一)await db.execute('''CREATE TABLE $tableUsers ($columnId INTEGER PRIMARY KEY AUTOINCREMENT, // 用戶ID,自增主鍵$columnName TEXT NOT NULL, // 用戶姓名,非空$columnEmail TEXT NOT NULL UNIQUE // 用戶郵箱,非空且唯一)''');}// 插入用戶數據的方法Future<int> insertUser(Map<String, dynamic> user) async {// 獲取數據庫實例Database db = await database;// 插入數據到 users 表,返回插入的行IDreturn await db.insert(tableUsers, user);}// 查詢所有用戶的方法Future<List<Map<String, dynamic>>> getAllUsers() async {// 獲取數據庫實例Database db = await database;// 查詢 users 表,返回所有用戶數據return await db.query(tableUsers);}// 根據ID查詢用戶的方法Future<Map<String, dynamic>?> getUserById(int id) async {// 獲取數據庫實例Database db = await database;// 查詢 users 表,查找指定ID的用戶List<Map<String, dynamic>> result = await db.query(tableUsers,where: '$columnId = ?', // 查詢條件whereArgs: [id], // 查詢參數);// 如果查詢結果不為空,返回第一個結果;否則返回 nullreturn result.isNotEmpty ? result.first : null;}// 更新用戶數據的方法Future<int> updateUser(Map<String, dynamic> user) async {// 獲取數據庫實例Database db = await database;// 更新 users 表中的指定用戶數據,返回更新的行數return await db.update(tableUsers,user,where: '$columnId = ?', // 更新條件whereArgs: [user[columnId]], // 更新參數);}// 刪除用戶的方法Future<int> deleteUser(int id) async {// 獲取數據庫實例Database db = await database;// 刪除 users 表中的指定用戶,返回刪除的行數return await db.delete(tableUsers,where: '$columnId = ?', // 刪除條件whereArgs: [id], // 刪除參數);}// 關閉數據庫的方法Future<void> closeDatabase() async {// 如果數據庫實例不為空,則關閉數據庫連接if (_database != null) {await _database!.close();_database = null;}}
}
代碼說明
常量定義:
dbName
:定義數據庫文件的名稱。
dbVersion
:定義數據庫的版本號,用于版本控制和升級。
tableUsers
:定義存儲用戶信息的表名。
columnId
、columnName
和columnEmail
:定義表中的字段名。數據庫實例:
_database
:私有變量,用于存儲數據庫連接實例。獲取數據庫實例:
database
:公共方法,用于獲取數據庫實例。如果數據庫已經初始化,則直接返回;否則調用_initDatabase
初始化數據庫。初始化數據庫:
_initDatabase
:獲取數據庫存儲路徑,并打開或創建數據庫文件。如果數據庫不存在,則調用_onCreate
方法創建表結構。創建表:
_onCreate
:創建users
表,包含三個字段:id
(自增主鍵)、name
(非空)、數據操作方法:
insertUser
:插入用戶數據到users
表,返回插入的行ID。
getAllUsers
:查詢users
表,返回所有用戶數據。
getUserById
:根據用戶ID查詢用戶數據,返回查詢結果或null
。
updateUser
:更新指定用戶的數據,返回更新的行數。
deleteUser
:刪除指定用戶,返回刪除的行數。
closeDatabase
:關閉數據庫連接,釋放資源。通過這些注釋,你可以更清晰地理解代碼的邏輯和功能,便于在項目中使用和維護。
4、main 二
import 'package:flutter/material.dart'; // 導入 Flutter 的 Material 組件庫
import 'database_helper.dart'; // 導入封裝的 DatabaseHelper 類void main() async {// 確保 Flutter 綁定初始化// 在使用 Flutter 的異步操作(如數據庫操作)之前,必須調用此方法來初始化 Flutter 的綁定。// 這是 Flutter 應用程序啟動時的必要步驟,確保可以使用 Flutter 提供的異步功能。WidgetsFlutterBinding.ensureInitialized();// 創建 DatabaseHelper 的實例// DatabaseHelper 是一個封裝類,用于管理用戶數據的保存、查詢、更新和刪除等操作。var dbHelper = DatabaseHelper();// 插入用戶數據// 調用 DatabaseHelper 的 insertUser 方法,將用戶數據(姓名和郵箱)插入到數據庫中。// 這里插入了一個示例用戶,姓名為 'John Doe',郵箱為 'john.doe@example.com'。await dbHelper.insertUser({'name': 'John Doe','email': 'john.doe@example.com'});// 查詢所有用戶// 調用 DatabaseHelper 的 getAllUsers 方法,查詢數據庫中的所有用戶數據。// 返回的是一個包含所有用戶信息的列表,每個用戶信息是一個 Map。List<Map<String, dynamic>> users = await dbHelper.getAllUsers();// 打印所有用戶數據print('All users: $users');// 根據ID查詢用戶// 調用 DatabaseHelper 的 getUserById 方法,通過用戶ID查詢特定用戶的數據。// 這里查詢ID為1的用戶。Map<String, dynamic>? user = await dbHelper.getUserById(1);// 打印查詢到的用戶數據print('User with ID 1: $user');// 更新用戶數據// 調用 DatabaseHelper 的 updateUser 方法,更新特定用戶的數據。// 這里將ID為1的用戶姓名更新為 'Jane Doe',郵箱更新為 'jane.doe@example.com'。await dbHelper.updateUser({'id': 1,'name': 'Jane Doe','email': 'jane.doe@example.com'});// 查詢更新后的用戶// 再次調用 getUserById 方法,查詢更新后的用戶數據。user = await dbHelper.getUserById(1);// 打印更新后的用戶數據print('Updated user with ID 1: $user');// 刪除用戶// 調用 DatabaseHelper 的 deleteUser 方法,刪除特定用戶。// 這里刪除ID為1的用戶。await dbHelper.deleteUser(1);// 查詢所有用戶(驗證刪除操作)// 再次調用 getAllUsers 方法,查詢數據庫中的所有用戶數據,驗證刪除操作是否成功。users = await dbHelper.getAllUsers();// 打印刪除后的所有用戶數據print('All users after deletion: $users');// 關閉數據庫// 調用 DatabaseHelper 的 closeDatabase 方法,關閉數據庫連接,釋放資源。await dbHelper.closeDatabase();
}
代碼說明
導入必要的庫:
flutter/material.dart
:導入 Flutter 的 Material 組件庫,用于構建 Flutter 應用。
database_helper.dart
:導入封裝的DatabaseHelper
類,該類提供了數據庫操作的接口。初始化 Flutter 綁定:
WidgetsFlutterBinding.ensureInitialized()
:在使用 Flutter 的異步操作之前,必須調用此方法來初始化 Flutter 的綁定。這是 Flutter 應用程序啟動時的必要步驟。創建
DatabaseHelper
實例:
var dbHelper = DatabaseHelper()
:創建DatabaseHelper
的實例,用于后續的數據庫操作。插入用戶數據:
await dbHelper.insertUser({...})
:調用DatabaseHelper
的insertUser
方法,將用戶數據(姓名和郵箱)插入到數據庫中。查詢所有用戶:
List<Map<String, dynamic>> users = await dbHelper.getAllUsers()
:調用DatabaseHelper
的getAllUsers
方法,查詢數據庫中的所有用戶數據。
print('All users: $users')
:打印所有用戶數據。根據ID查詢用戶:
Map<String, dynamic>? user = await dbHelper.getUserById(1)
:調用DatabaseHelper
的getUserById
方法,通過用戶ID查詢特定用戶的數據。
print('User with ID 1: $user')
:打印查詢到的用戶數據。更新用戶數據:
await dbHelper.updateUser({...})
:調用DatabaseHelper
的updateUser
方法,更新特定用戶的數據。查詢更新后的用戶:
user = await dbHelper.getUserById(1)
:再次調用getUserById
方法,查詢更新后的用戶數據。
print('Updated user with ID 1: $user')
:打印更新后的用戶數據。刪除用戶:
await dbHelper.deleteUser(1)
:調用DatabaseHelper
的deleteUser
方法,刪除特定用戶。查詢所有用戶(驗證刪除操作):
users = await dbHelper.getAllUsers()
:再次調用getAllUsers
方法,查詢數據庫中的所有用戶數據,驗證刪除操作是否成功。
print('All users after deletion: $users')
:打印刪除后的所有用戶數據。關閉數據庫:
await dbHelper.closeDatabase()
:調用DatabaseHelper
的closeDatabase
方法,關閉數據庫連接,釋放資源。通過這些注釋,你可以更清晰地理解代碼的邏輯和功能,便于在項目中使用和維護。