在 Flutter 應用開發中,本地存儲是必不可少的功能。無論是保存用户登錄信息、應用配置,還是存儲結構化的業務數據,都需要選擇合適的本地存儲方案。Flutter 提供了多種本地存儲方式,涵蓋輕量級鍵值對存儲、NoSQL 數據庫和關係型數據庫等,滿足不同場景的需求。本文將詳細解析 Flutter 中主流的本地存儲方案,包括其特點、用法和適用場景。
一、Flutter 本地存儲的常見場景與分類
Flutter 本地存儲主要用於以下場景:
- 保存輕量級配置信息(如主題模式、語言設置);
- 緩存網絡數據,減少重複請求;
- 存儲結構化業務數據(如本地訂單、收藏列表);
- 持久化用户登錄狀態、個人信息等。
根據存儲數據的類型和結構,Flutter 本地存儲可分為三類:
- 鍵值對存儲:適合存儲簡單的鍵值型數據,如
SharedPreferences、Hive(輕量 NoSQL,也支持鍵值對); - NoSQL 數據庫:適合存儲非結構化或半結構化數據,如
Hive、ObjectBox; - 關係型數據庫:適合存儲結構化、關聯度高的數據,如
SQFlite、Drift。
二、SharedPreferences:輕量級鍵值對存儲
SharedPreferences是 Flutter 中最常用的輕量級存儲方案,本質上是對 Android 的SharedPreferences和 iOS 的NSUserDefaults的封裝,適用於存儲簡單的鍵值對數據(如字符串、數字、布爾值)。
1. 集成與基本使用
首先在pubspec.yaml中添加依賴:
dependencies:
shared_preferences: ^2.2.2
核心操作包括存、取、刪、清:
import 'package:shared_preferences/shared_preferences.dart';
// 存儲數據
Future<void> saveData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('username', 'FlutterDev'); // 存儲字符串
await prefs.setInt('age', 25); // 存儲整數
await prefs.setBool('isLogin', true); // 存儲布爾值
await prefs.setStringList('hobbies', ['coding', 'reading']); // 存儲字符串列表
}
// 獲取數據
Future<void> getData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? username = prefs.getString('username');
int? age = prefs.getInt('age');
bool? isLogin = prefs.getBool('isLogin');
List<String>? hobbies = prefs.getStringList('hobbies');
print("用户名:$username,年齡:$age,是否登錄:$isLogin,愛好:$hobbies");
}
// 刪除數據
Future<void> removeData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.remove('username'); // 刪除指定鍵的數據
}
// 清空所有數據
Future<void> clearData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.clear();
}
2. 適用場景與侷限性
適用場景:存儲應用配置、用户偏好設置、簡單的狀態標記(如是否首次啓動)。侷限性:
- 僅支持基本數據類型,無法存儲複雜對象;
- 存儲容量有限,不適合存儲大量數據;
- 性能一般,頻繁讀寫可能導致卡頓。
三、Hive:高性能 NoSQL 鍵值數據庫
Hive是專為 Flutter 設計的輕量級 NoSQL 數據庫,基於鍵值對存儲,支持複雜對象序列化,性能遠超SharedPreferences,且無需原生依賴,跨平台兼容性好。
1. 集成與初始化
添加依賴並配置:
dependencies:
hive: ^2.2.3
hive_flutter: ^1.1.0
dev_dependencies:
hive_generator: ^1.1.5
build_runner: ^2.4.6
初始化 Hive:
import 'package:hive_flutter/hive_flutter.dart';
void initHive() async {
await Hive.initFlutter(); // 初始化Hive
await Hive.openBox('userBox'); // 打開名為userBox的盒子(類似數據庫表)
}
2. 基本操作
Hive 的核心操作圍繞 Box(盒子) 展開,一個 Box 相當於一個數據集:
// 存儲數據
void saveToHive() {
final box = Hive.box('userBox');
box.put('user', {'name': 'FlutterDev', 'age': 25}); // 存儲Map
box.put('scores', [90, 85, 95]); // 存儲列表
}
// 獲取數據
void getFromHive() {
final box = Hive.box('userBox');
var user = box.get('user');
var scores = box.get('scores');
print("用户信息:$user,分數:$scores");
}
// 自定義對象存儲(需序列化)
// 1. 創建實體類並添加註解
import 'package:hive/hive.dart';
part 'person.g.dart'; // 生成的序列化代碼
@HiveType(typeId: 0)
class Person {
@HiveField(0)
final String name;
@HiveField(1)
final int age;
Person({required this.name, required this.age});
}
// 2. 運行構建命令生成序列化代碼:flutter pub run build_runner build
// 3. 註冊適配器並存儲對象
void saveCustomObject() async {
Hive.registerAdapter(PersonAdapter()); // 註冊適配器
final box = Hive.box('userBox');
box.put('person', Person(name: 'FlutterDev', age: 25));
Person? person = box.get('person');
print("自定義對象:${person?.name},${person?.age}");
}
3. 適用場景與優勢
適用場景:存儲複雜對象、中等規模的本地數據、需要高性能讀寫的場景(如緩存列表數據)。優勢:
- 支持複雜對象序列化,無需手動轉換;
- 純 Dart 實現,跨平台無原生依賴;
- 讀寫速度快,性能優於 SQFlite;
- 支持加密存儲,保護敏感數據。
四、SQFlite:SQLite 的 Flutter 封裝
SQFlite是 Flutter 對 SQLite 數據庫的封裝,適用於存儲結構化、關聯度高的關係型數據,如電商訂單、本地通訊錄等。
1. 集成與數據庫初始化
添加依賴:
dependencies:
sqflite: ^2.3.0
path: ^1.8.3
初始化數據庫並創建表:
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseHelper {
static final DatabaseHelper instance = DatabaseHelper._init();
static Database? _database;
DatabaseHelper._init();
// 獲取數據庫實例
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDB('notes.db');
return _database!;
}
// 初始化數據庫
Future<Database> _initDB(String filePath) async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, filePath);
return await openDatabase(path, version: 1, onCreate: _createDB);
}
// 創建表
Future<void> _createDB(Database db, int version) async {
await db.execute('''
CREATE TABLE notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
)
''');
}
}
2. CRUD 操作
// 插入數據
Future<int> insertNote(Map<String, dynamic> note) async {
final db = await DatabaseHelper.instance.database;
return await db.insert('notes', note);
}
// 查詢所有數據
Future<List<Map<String, dynamic>>> queryAllNotes() async {
final db = await DatabaseHelper.instance.database;
return await db.query('notes');
}
// 更新數據
Future<int> updateNote(Map<String, dynamic> note) async {
final db = await DatabaseHelper.instance.database;
int id = note['id'];
return await db.update('notes', note, where: 'id = ?', whereArgs: [id]);
}
// 刪除數據
Future<int> deleteNote(int id) async {
final db = await DatabaseHelper.instance.database;
return await db.delete('notes', where: 'id = ?', whereArgs: [id]);
}
3. 適用場景與侷限性
適用場景:存儲結構化、有複雜關聯關係的數據,如多表關聯的業務數據。侷限性:
- 需要編寫 SQL 語句,學習成本較高;
- 性能略低於 Hive,適合數據量中等的場景;
- 跨平台需適配不同系統的 SQLite 版本。
五、Drift:類型安全的 SQL 數據庫
Drift(原 Moor)是基於 SQLite 的高級封裝,採用 Dart 代碼生成的方式實現類型安全的數據庫操作,無需手動編寫 SQL 語句,開發效率更高。
1. 集成與基本使用
添加依賴:
dependencies:
drift: ^2.12.0
sqlite3_flutter_libs: ^0.5.16
path_provider: ^2.1.1
path: ^1.8.3
dev_dependencies:
drift_dev: ^2.12.0
build_runner: ^2.4.6
定義數據庫表和操作:
import 'package:drift/drift.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:drift/native.dart';
import 'dart:io';
// 定義表
class Notes extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text().notNull()();
TextColumn get content => text().nullable()();
DateTimeColumn get createTime => dateTime().withDefault(currentDateAndTime)();
}
// 定義數據庫類
part 'database.g.dart';
@DriftDatabase(tables: [Notes])
class AppDatabase extends _$AppDatabase {
AppDatabase() : super(_openConnection());
@override
int get schemaVersion => 1;
// 插入筆記
Future<int> insertNote(NotesCompanion note) => into(notes).insert(note);
// 查詢所有筆記
Future<List<Note>> getAllNotes() => select(notes).get();
// 更新筆記
Future<int> updateNote(Note note) => update(notes).replace(note);
// 刪除筆記
Future<int> deleteNote(Note note) => delete(notes).delete(note);
}
// 打開數據庫連接
LazyDatabase _openConnection() {
return LazyDatabase(() async {
final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, 'notes.db'));
return NativeDatabase(file);
});
}
運行構建命令生成代碼:flutter pub run build_runner build,之後即可調用數據庫方法:
void testDrift() async {
final db = AppDatabase();
// 插入數據
await db.insertNote(NotesCompanion(title: Value('Flutter筆記'), content: Value('Drift數據庫學習')));
// 查詢數據
List<Note> notes = await db.getAllNotes();
print(notes);
}
2. 優勢與適用場景
優勢:
- 類型安全,編譯期檢查 SQL 錯誤;
- 支持 Dart 語法代替 SQL 語句,開發更便捷;
- 支持流查詢(
watch方法),數據變化時自動刷新 UI; - 兼容 SQLite 所有特性,支持複雜查詢和事務。
適用場景:需要類型安全、複雜查詢的關係型數據存儲場景,適合中大型 Flutter 應用。
六、Flutter 本地存儲方案的選擇建議
- 簡單鍵值對數據:優先選擇
SharedPreferences,開發成本低;若需要存儲複雜對象或追求高性能,選擇Hive; - 非結構化 / 半結構化數據:選擇
Hive,兼顧性能和易用性; - 結構化、關聯度高的數據:
- 若熟悉 SQL 且數據量較小,選擇
SQFlite; - 若追求類型安全和開發效率,選擇
Drift;
- 大數據量、高性能要求:考慮
ObjectBox(另一個高性能 NoSQL 數據庫,適合海量數據存儲)。
七、本地存儲的注意事項
- 數據加密:敏感數據(如用户密碼、token)需加密存儲,可使用
encrypt包結合 Hive/SQFlite 實現; - 數據清理:定期清理過期緩存數據,避免佔用過多設備存儲;
- 事務管理:批量操作數據時使用事務,確保數據一致性;
- 錯誤處理:捕獲存儲操作中的異常(如數據庫打開失敗、讀寫權限不足),避免程序崩潰;
- 適配不同平台:注意 Android 和 iOS 的存儲路徑、權限差異,確保跨平台兼容性。
八、總結
Flutter 提供了豐富的本地存儲方案,從輕量級的SharedPreferences到高性能的Hive,再到關係型的SQFlite和Drift,每種方案都有其適用場景。在實際開發中,需根據數據類型、規模和性能需求選擇合適的存儲方式,並遵循最佳實踐確保數據安全和應用穩定性。掌握這些本地存儲技術,能讓 Flutter 應用在離線場景下也能提供流暢的用户體驗。