Flutter'da Yerel Depolama: Hive, SharedPreferences ve SQLite
Yerel depolama seçimi kullanım senaryosuna göre değişir: tema/dil tercihleri gibi basit ayarlar için SharedPreferences, yapılandırılmamış nesne depolamak için Hive, karmaşık sorgular ve ilişkili tablolar için SQLite (Drift) tercih edilir.
SharedPreferences: Basit Anahtar-Değer Deposu
// pubspec: shared_preferences: ^2.3.2
class AppSettings {
static const _themeKey = 'theme_mode';
static const _languageKey = 'language';
static const _onboardedKey = 'onboarded';
final SharedPreferences _prefs;
AppSettings(this._prefs);
// Factory method
static Future<AppSettings> create() async {
final prefs = await SharedPreferences.getInstance();
return AppSettings(prefs);
}
ThemeMode get themeMode {
final value = _prefs.getString(_themeKey);
return ThemeMode.values.firstWhere(
(e) => e.name == value,
orElse: () => ThemeMode.system,
);
}
Future<void> setThemeMode(ThemeMode mode) =>
_prefs.setString(_themeKey, mode.name);
String get language => _prefs.getString(_languageKey) ?? 'tr';
Future<void> setLanguage(String code) => _prefs.setString(_languageKey, code);
bool get isOnboarded => _prefs.getBool(_onboardedKey) ?? false;
Future<void> markOnboarded() => _prefs.setBool(_onboardedKey, true);
Future<void> clearAll() => _prefs.clear();
}
// GetIt ile kullanım
@module
abstract class StorageModule {
@preResolve
@lazySingleton
Future<AppSettings> get settings => AppSettings.create();
}
Hive: Hızlı NoSQL Nesne Deposu
Hive, dart nesnelerini doğrudan diske yazar. Box sistemi ile her nesne türü kendi kutusunda saklanır:
// pubspec: hive_flutter: ^1.1.0, hive_generator: ^2.0.1
// Model — TypeAdapter üretimi için annotation
part 'product.g.dart';
@HiveType(typeId: 0)
class Product extends HiveObject {
@HiveField(0) late String id;
@HiveField(1) late String title;
@HiveField(2) late double price;
@HiveField(3) late int stock;
@HiveField(4) late DateTime updatedAt;
Product({
required this.id,
required this.title,
required this.price,
required this.stock,
required this.updatedAt,
});
}
// Adapter üretimi:
// dart run build_runner build
// Başlatma (main.dart)
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter(ProductAdapter());
await Hive.openBox<Product>('products');
await Hive.openBox('settings'); // genel amaçlı
runApp(const MyApp());
}
// Repository
class HiveProductRepository {
Box<Product> get _box => Hive.box<Product>('products');
List<Product> getAll() => _box.values.toList();
Product? getById(String id) =>
_box.values.firstWhere((p) => p.id == id, orElse: () => throw Exception());
Future<void> save(Product product) => _box.put(product.id, product);
Future<void> delete(String id) => _box.delete(id);
Future<void> saveAll(List<Product> products) {
final map = {for (var p in products) p.id: p};
return _box.putAll(map);
}
// Reactive — Stream ile değişiklikleri dinle
Stream<BoxEvent> watch() => _box.watch();
}
// Widget'ta stream builder ile reactive güncelleme
ValueListenableBuilder<Box<Product>>(
valueListenable: Hive.box<Product>('products').listenable(),
builder: (context, box, _) {
final products = box.values.toList();
return ListView.builder(
itemCount: products.length,
itemBuilder: (_, i) => ProductTile(product: products[i]),
);
},
)
Drift (SQLite): Tip Güvenli İlişkisel Veritabanı
Drift (eski adıyla Moor), SQLite üzerine tip güvenli Dart API'si sunar. Karmaşık sorgular ve tablolar arası ilişkiler için idealdir:
// pubspec: drift: ^2.18.0, drift_flutter: ^0.2.2, sqlite3_flutter_libs: ^0.5.0
// dev: drift_dev: ^2.18.0, build_runner
// lib/database/app_database.dart
part 'app_database.g.dart';
// Tablo tanımı
class Notes extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text().withLength(min: 1, max: 200)();
TextColumn get content => text()();
TextColumn get categorySlug => text().nullable()();
BoolColumn get isPinned => boolean().withDefault(const Constant(false))();
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
}
class Categories extends Table {
TextColumn get slug => text()();
TextColumn get name => text()();
IntColumn get color => integer()();
@override
Set<Column> get primaryKey => {slug};
}
// Veritabanı sınıfı
@DriftDatabase(tables: [Notes, Categories])
class AppDatabase extends _$AppDatabase {
AppDatabase() : super(_openConnection());
@override
int get schemaVersion => 1;
// CRUD sorgular
Future<List<Note>> getAllNotes() => select(notes).get();
Stream<List<Note>> watchPinnedNotes() =>
(select(notes)..where((n) => n.isPinned)).watch();
Future<List<Note>> searchNotes(String query) =>
(select(notes)
..where((n) => n.title.contains(query) | n.content.contains(query))
..orderBy([(n) => OrderingTerm.desc(n.createdAt)]))
.get();
Future<int> insertNote(NotesCompanion note) => into(notes).insert(note);
Future<bool> updateNote(Note note) => update(notes).replace(note);
Future<int> deleteNote(int id) =>
(delete(notes)..where((n) => n.id.equals(id))).go();
// Join sorgusu
Future<List<NoteWithCategory>> getNotesWithCategories() {
final query = select(notes).join([
leftOuterJoin(categories,
categories.slug.equalsExp(notes.categorySlug)),
]);
return query.map((row) => NoteWithCategory(
note: row.readTable(notes),
category: row.readTableOrNull(categories),
)).get();
}
// Migration
@override
MigrationStrategy get migration => MigrationStrategy(
onUpgrade: (m, from, to) async {
if (from == 1) {
await m.addColumn(notes, notes.isPinned);
}
},
);
}
QueryExecutor _openConnection() => driftDatabase(name: 'app_db');
// Kullanım
final db = AppDatabase();
await db.insertNote(NotesCompanion.insert(
title: 'Flutter Notları',
content: 'Drift gerçekten pratik...',
));
final notes = await db.getAllNotes();
StreamBuilder<List<Note>>(
stream: db.watchPinnedNotes(),
builder: (context, snap) => NotesList(notes: snap.data ?? []),
)
Hangi Çözümü Seçmeli?
Basit ayarlar ve tercihler için SharedPreferences yeterlidir. Nesne listelerini veya cache verilerini saklamak için Hive idealdir. Karmaşık sorgular, filtreler ve tablolar arası ilişkiler gerekiyorsa Drift tercih edin. Şifreli veri için hive_flutter'ın şifreleme desteğini veya sqlcipher'ı kullanabilirsiniz.