Local Storage
Local Storage
រក្សាទុកទិន្នន័យក្នុងឧបករណ៍ (device)។ Flutter មាន storage solutions ជាច្រើនប្រភេទ សម្រាប់ការប្រើប្រាស់ផ្សេងៗគ្នា។
� Storage Types Theory
Storage Comparison:
Storage Type | Data Size | Data Type | Use Case |
---|---|---|---|
SharedPreferences | តូច (KB) | String, int, bool, double, List<String> | Settings, user preferences, flags |
SQLite Database | មធ្យម-ធំ (MB-GB) | Structured relational data | Complex data, relationships, queries |
File Storage | ធំ (MB-GB) | Images, videos, documents, JSON | Media files, large documents |
Secure Storage | តូច (KB) | Encrypted strings | Passwords, tokens, sensitive data |
When to Use Which Storage?
Storage Decision Tree
❓ តើទិន្នន័យជាអ្វី?
├─ 🔐 Sensitive data (password, token)
│ └─ ✅ Use: flutter_secure_storage
│
├─ ⚙️ Settings/Preferences (theme, language)
│ └─ ✅ Use: shared_preferences
│
├─ 📊 Complex structured data (users, products)
│ └─ ✅ Use: SQLite (sqflite)
│
├─ 🖼️ Files (images, videos, PDFs)
│ └─ ✅ Use: File Storage (path_provider)
│
└─ ☁️ Sync across devices
└─ ✅ Use: Firebase/Cloud storage
📦 SharedPreferences (Key-Value Storage)
Best for: User settings, simple flags, preferences
# pubspec.yaml
dependencies:
shared_preferences: ^2.2.0
import 'package:shared_preferences/shared_preferences.dart';
// រក្សាទុក
Future<void> saveData() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('name', 'សុខា');
await prefs.setInt('age', 20);
await prefs.setBool('isLogin', true);
}
// អាន
Future<void> loadData() async {
final prefs = await SharedPreferences.getInstance();
String? name = prefs.getString('name');
int? age = prefs.getInt('age');
bool? isLogin = prefs.getBool('isLogin');
}
Complete SharedPreferences Example:
class PreferencesService {
static const String KEY_THEME = 'theme_mode';
static const String KEY_LANGUAGE = 'language';
static const String KEY_USER_ID = 'user_id';
// Save settings
Future<void> saveSettings({
required String theme,
required String language,
required int userId,
}) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(KEY_THEME, theme);
await prefs.setString(KEY_LANGUAGE, language);
await prefs.setInt(KEY_USER_ID, userId);
}
// Load settings
Future<Map<String, dynamic>> loadSettings() async {
final prefs = await SharedPreferences.getInstance();
return {
'theme': prefs.getString(KEY_THEME) ?? 'light',
'language': prefs.getString(KEY_LANGUAGE) ?? 'km',
'userId': prefs.getInt(KEY_USER_ID) ?? 0,
};
}
// Remove specific key
Future<void> removeKey(String key) async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove(key);
}
// Clear all data
Future<void> clearAll() async {
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
}
}
🗄️ SQLite Database (sqflite)
Best for: Complex data with relationships, querying, filtering
# pubspec.yaml
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 _createDB(Database db, int version) async {
await db.execute('''
CREATE TABLE notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT NOT NULL,
created_at TEXT NOT NULL
)
''');
}
// Create (Insert)
Future<int> insertNote(Map<String, dynamic> note) async {
final db = await database;
return await db.insert('notes', note);
}
// Read (Select)
Future<List<Map<String, dynamic>>> getAllNotes() async {
final db = await database;
return await db.query('notes', orderBy: 'created_at DESC');
}
Future<Map<String, dynamic>?> getNoteById(int id) async {
final db = await database;
final results = await db.query(
'notes',
where: 'id = ?',
whereArgs: [id],
);
return results.isNotEmpty ? results.first : null;
}
// Update
Future<int> updateNote(int id, Map<String, dynamic> note) async {
final db = await database;
return await db.update(
'notes',
note,
where: 'id = ?',
whereArgs: [id],
);
}
// Delete
Future<int> deleteNote(int id) async {
final db = await database;
return await db.delete(
'notes',
where: 'id = ?',
whereArgs: [id],
);
}
// Close database
Future close() async {
final db = await database;
db.close();
}
}
📁 File Storage (path_provider)
Best for: Images, videos, large files, JSON files
# pubspec.yaml
dependencies:
path_provider: ^2.1.0
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'dart:convert';
class FileStorageService {
// Get application documents directory
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
// Save text file
Future<File> saveTextFile(String filename, String content) async {
final path = await _localPath;
final file = File(path + '/' + filename);
return file.writeAsString(content);
}
// Read text file
Future<String> readTextFile(String filename) async {
try {
final path = await _localPath;
final file = File(path + '/' + filename);
return await file.readAsString();
} catch (e) {
return '';
}
}
// Save JSON
Future<File> saveJson(String filename, Map<String, dynamic> data) async {
final jsonString = jsonEncode(data);
return saveTextFile(filename, jsonString);
}
// Read JSON
Future<Map<String, dynamic>> readJson(String filename) async {
final jsonString = await readTextFile(filename);
if (jsonString.isEmpty) return {};
return jsonDecode(jsonString);
}
// Save image
Future<File> saveImage(String filename, List<int> bytes) async {
final path = await _localPath;
final file = File(path + '/' + filename);
return file.writeAsBytes(bytes);
}
// Delete file
Future<void> deleteFile(String filename) async {
final path = await _localPath;
final file = File(path + '/' + filename);
if (await file.exists()) {
await file.delete();
}
}
// List all files
Future<List<String>> listFiles() async {
final path = await _localPath;
final directory = Directory(path);
final files = directory.listSync();
return files.map((file) => file.path.split('/').last).toList();
}
}
🔐 Secure Storage (flutter_secure_storage)
Best for: Passwords, API tokens, sensitive user data
# pubspec.yaml
dependencies:
flutter_secure_storage: ^9.0.0
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class SecureStorageService {
final _storage = FlutterSecureStorage();
// Save secure data
Future<void> saveToken(String token) async {
await _storage.write(key: 'auth_token', value: token);
}
Future<void> saveCredentials(String email, String password) async {
await _storage.write(key: 'email', value: email);
await _storage.write(key: 'password', value: password);
}
// Read secure data
Future<String?> getToken() async {
return await _storage.read(key: 'auth_token');
}
Future<Map<String, String?>> getCredentials() async {
final email = await _storage.read(key: 'email');
final password = await _storage.read(key: 'password');
return {'email': email, 'password': password};
}
// Delete secure data
Future<void> deleteToken() async {
await _storage.delete(key: 'auth_token');
}
// Clear all secure data
Future<void> clearAll() async {
await _storage.deleteAll();
}
}
🎯 Real-World Example: User Session Manager
class SessionManager {
final _prefs = SharedPreferences.getInstance();
final _secureStorage = FlutterSecureStorage();
// Login - Save session
Future<void> login({
required int userId,
required String name,
required String email,
required String token,
}) async {
// Save non-sensitive data in SharedPreferences
final prefs = await _prefs;
await prefs.setInt('user_id', userId);
await prefs.setString('user_name', name);
await prefs.setString('user_email', email);
await prefs.setBool('is_logged_in', true);
// Save sensitive data in Secure Storage
await _secureStorage.write(key: 'auth_token', value: token);
}
// Check if logged in
Future<bool> isLoggedIn() async {
final prefs = await _prefs;
return prefs.getBool('is_logged_in') ?? false;
}
// Get current user
Future<Map<String, dynamic>?> getCurrentUser() async {
final prefs = await _prefs;
final isLoggedIn = prefs.getBool('is_logged_in') ?? false;
if (!isLoggedIn) return null;
return {
'userId': prefs.getInt('user_id'),
'name': prefs.getString('user_name'),
'email': prefs.getString('user_email'),
'token': await _secureStorage.read(key: 'auth_token'),
};
}
// Logout - Clear session
Future<void> logout() async {
final prefs = await _prefs;
await prefs.clear();
await _secureStorage.deleteAll();
}
}
💡 Best Practices:
- ✅ Use SharedPreferences for simple settings only
- ✅ Use SQLite for complex structured data
- ✅ Use Secure Storage for passwords and tokens
- ✅ Use File Storage for large files and media
- ✅ Always handle read/write errors with try-catch
- ✅ Close database connections when done
- ✅ Never store sensitive data in SharedPreferences
⚠️ Security Warning:
- ❌ Never store passwords in SharedPreferences (not encrypted)
- ❌ Don't store large data in SharedPreferences (causes lag)
- ❌ Don't use SQLite for simple key-value data (overkill)
- ✅ Always use flutter_secure_storage for sensitive data
💡 ជំនួយ: SharedPreferences សម្រាប់រក្សាទិន្នន័យតូចៗ។ SQLite សម្រាប់ទិន្នន័យស្មុគស្មាញ។ Secure Storage សម្រាប់ទិន្នន័យសម្ងាត់។