Merhaba arkadaşlar Blogger uygulaması üzerinde yeni yazılar yayınlama kararı aldıktan sonra neler yazarım diye düşünürken Flutter serisi yayınlamak mantıklı geldi. Çünkü bende mobil dünyasına yeni girip öğrendiklerimi öğrenmiş miyim sorgusunu anlatarak öğrenmek isteyenlerdenim.
Her neyse lafın kısası makuldur. Seriye Hive Depolama Yöntemi ile başlayalım arkadaşlar;
Flutter da Depolama olarak bir çok yöntem olduğu JavaScript de kullandığımız metodolojiye uygun LocalStorage yapısını kullanacağız.
Bu tabiki paketler serisi üzerinden gerçekleşecek bir yapı javascript deki gibi kolay bir yapı değil.
Öncelikle kurulum yapılması gereken paketler serisini bugün ihtibariyle sürüm notlarını aşağıda görsel olarak paylaşacağım ve sonrasında paket linklerini pub.dev sitesinde ekleyeceğim.
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
google_fonts: ^2.3.0
flutter_datetime_picker: ^1.5.1
uuid: ^3.0.5
intl: ^0.17.0
hive: ^2.0.5
hive_flutter: ^1.1.0
build_runner: ^2.1.7
hive_generator: ^1.1.2
get_it: ^7.2.0
Öncelikle kurulu olan paketler bize basit bir todo uygulaması üzerinden hizmet ediyor.
Burada google_fonts ve datetime_picker hepimizin bildiği terimler onları geçiyorum.
uuid: ^3.0.5
intl: ^0.17.0
hive: ^2.0.5
hive_flutter: ^1.1.0
build_runner: ^2.1.7
hive_generator: ^1.1.2
intl paketi de datetime picker üzerinden seçilen tarih formatını ayarlamak için kullandığımız bir paket.
hive versiyon olarak güncel tarihte ^2.0.5 üzerinde yayında
paket linki: https://pub.dev/packages/hive
installing durumları hakkında bilgi paylaşmak istemiyorum çünkü bu süreç pub.dev üzerinde zaten mevcut.
hive_flutter versiyon ^1.1.0
Link: https://pub.dev/packages/hive_flutter/install
hive_generator versiyon ^1.1.2
Link: https://pub.dev/packages/hive_generator
ve son olarak da build_runner paketimiz var bunları version linklerini paylaştıktan sonra kısa bir bilgilendirme yaparak küçük bir todo uygulaması yapmış olacağız.
build_runner versiyon ^2.1.7
Link: https://pub.dev/packages/build_runner
Kısaca paketlerimizin pub.dev üzerinde ki durumları bu şekilde.
Model olarak task class'ımız mevcut. Task model'inde kullandığımız alanlarımız id,name,createdAt ve isCompleted alanları;
import 'package:hive/hive.dart';
import 'package:uuid/uuid.dart';
part 'task_model.g.dart';
@HiveType(typeId: 1)
class Task extends HiveObject {
@HiveField(0)
final String id;
@HiveField(1)
String name;
@HiveField(2)
final DateTime createdAt;
@HiveField(3)
bool isCompleted;
Task(
{required this.id,
required this.name,
required this.createdAt,
required this.isCompleted});
factory Task.create({required String name, required DateTime createdAt}) {
return Task(
id: const Uuid().v1(),
name: name,
createdAt: createdAt,
isCompleted: false);
}
}
hive paketi ile alanların index numaralarını belirttik ve required tanımlamalarını gerçekleştirdik. Aynı model içerisinde paket sayesinde extends edeceğimiz yeni model ismini de part içerisinde geçerek paketin yeni paket oluşturmasını sağladık.
Tabi bunları yaptıktan sonra proje ayağa kalkarken main methodu içerisinde tanımlamalarımızı da unutmayalım.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get_it/get_it.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:todo_app/data/local_storage.dart';
import 'package:todo_app/pages/home_page.dart';
import 'models/task_model.dart';
final locator = GetIt.instance;
Future<void> setupHive() async {
await Hive.initFlutter();
Hive.registerAdapter(TaskAdapter());
var taskBox = await Hive.openBox<Task>('tasks');
}
void setup() {
locator.registerSingleton<LocalStorage>(HiveLocalStorage());
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
//status bar kaybetmek için --> saat ve sarj bilgisi olan alan
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(statusBarColor: Colors.transparent));
await setupHive();
setup();
runApp(const MyApp());
}
Main.dart içerisinde setupHive methodu tanımlayarak Hive ait tanımlamaları içerisinde gerçekleştirdik. Sonrasında yaşam döngüsü olarak kaç kere ayağa kalkmasını istediğimiz durumlara özel singleton tanımalaması yaptık. Burada biz bir kerelik ayağa kalkmış locator nesnesi proje boyunca yeterli olacağı için ekstra başka bir yapı kullanma gereği görmedik.
Tabi bunları yapmadan önce hive paketinin kendi sayfasında generator türetmesini terminal ekranından çalıştırarak TaskAdapter modelini türetmesini yapmamız gerekiyor. Yoksa;
await Hive.initFlutter();
Hive.registerAdapter(TaskAdapter());
asenktron olarak Hive Flutter üzerinde initial ettiğimizde register ederken flutter TaskAdapter nesnesini arayacaktır.
TaskAdapter modelini elde etmek için hive paketinin generator üzerinden sağladığı kolaylık için kendi sitesinde yayınladığı kod
flutter packages pub run build_runner build
Kod bloğunu run ettikten sonra model klasörü içerisinde ;
Bu şekilde bir klasör yapısı ve models içerisinde
task_model.g.dart diye sınıfımız oluşmuştur. Burada dikkat etmemiz gereken durumlardan bir taneside
var taskBox = await Hive.openBox<Task>('tasks');
kod bloğunun model olarak kullandığımız local_storage.dart class içerisinde ki
_taskBox = Hive.box<Task>('tasks');
yapıyla aynı olması gerekiyor. Şimdi local_storage.dart nesnesi nereden çıktı diyenleri duyar gibiyim. Arkadaşlar bu da bizim sanal sınıfımız içerisinde bulunan Hive methodları için kullandığımız bir abstract classtır.
Olur ya bu yapıyı başka bir yöntem olan SqFlite üzerinde kullanmak isterseniz yapacağınız tek şey Hive üzerinde yaptığımız sanallaştırmayı bu sefer SqFlite üzerinde yapacaksınız.
local_storage.dart classı üzerine gelirsek orada sanal sınıflarımız nelermiş onlara da bakalım.
abstract class LocalStorage {
Future<void> addTask({required Task task});
Future<Task?> getTask({required String id});
Future<List<Task>> getAllTask();
Future<bool> deleteTask({required Task task});
Future<Task> updateTask({required Task task});
}
Bu abstract class içerisinde ki methodlar sayesinde hangi yöntem olursa olsun extends ederek o yapıyı rahat bir şekilde projeye entegre etmiş olacağız arkadaşlar.
Hive paketine ait sql sorgularını yazabilmek için yeni local method oluşturup onu extends ediyoruz.
class HiveLocalStorage extends LocalStorage {
late Box<Task> _taskBox;
HiveLocalStorage() {
//main methodunda ki ile aynı olmak zorunda 'tasks'
_taskBox = Hive.box<Task>('tasks');
}
@override
Future<void> addTask({required Task task}) async {
await _taskBox.put(task.id, task);
}
@override
Future<bool> deleteTask({required Task task}) async {
await task.delete();
return true;
}
@override
Future<List<Task>> getAllTask() async {
List<Task> _allTask = <Task>[];
_allTask = _taskBox.values.toList();
if (_allTask.isNotEmpty) {
_allTask.sort((Task a, Task b) => a.createdAt.compareTo(b.createdAt));
}
return _allTask;
}
@override
Future<Task?> getTask({required String id}) async {
if (_taskBox.containsKey(id)) {
return _taskBox.get(id);
} else {
return null;
}
}
@override
Future<Task> updateTask({required Task task}) async {
await task.save();
return task;
}
Burada klasik olan getAllTodo, add,delete ve update durumlarını hive yapısına özel doldurup local_storage kısmını tamamlamış oluyoruz.
Buraya kadar aslında kısaca alt yapıyı oluşturmuş oluyoruz ama görünür de tabi nasıl kullanacağımız ile alakalı bir bilgi paylaşmadık. Hadi şimdi de onu nasıl yapıyoruz anlatalım burada bitirelim.
Add methodu için;
todo eklemesi yapacağımız zaman, ekleme yapılacak widget veya page üzerinde local de global olarak local_storage.dart nesnesini tanımalaması yaparak başlıyoruz. Hani başta singleton olarak tanımladığımız yöntem aslında buraya hizmet ediyor.
late List<Task> _allTask;
late LocalStorage _localStorage;
@override
void initState() {
super.initState();
_localStorage = locator<LocalStorage>();
_allTask = <Task>[];
_getAllTaskDb();
initState içerisinde boş bir List<Task> nesnesi tanımlıyoruz sonrasında late kullanarak LocalStorage tanımlamasını yapıyoruz. _localStorage locator<LocalStorage>() üzerinden türeterek kullanıma açıyoruz singelton olarak.
if (value.length > 5) {
DatePicker.showTimePicker(context, showSecondsColumn: false,
onConfirm: (time) async {
var yeniEklenecekGorev =
Task.create(name: value, createdAt: time);
_allTask.add(yeniEklenecekGorev);
await _localStorage.addTask(task: yeniEklenecekGorev);
setState(() {});
});
Validator kontrolü sonrasında confirm olayını gerçekleştirirken de hem sanal listeme hemde hiv ile tanımladığım localstorage alanıma ekleme yapıyorum. Tabi bu methodların hepsi asenktron olacağı için async eklemeyi unutmuyoruz. Herhangi bir bloc provider kullanmadığımız için statefull yapısının bu değişiklikleri algılaması içinde setState(){} eklemeyi unutmuyoruz.
Delete methodu içerisinde aynı türetmeler sonrasında;
onDismissed: (direction) {
_allTask.removeAt(index);
_localStorage.deleteTask(task: _oAnkiEleman);
setState(() {});
},
onDismmised => sonrasında _localStorage.deleteTask(task:_oankieleman) göndererek setState(){} yapıyoruz.
Güncelleme işlemleri içinde;
widget.task.isCompleted = !widget.task.isCompleted;
_localStorage.updateTask(task: widget.task);
setState(() {});
updateTask methodunu sanal sınıfımızdan çağırarak task nesnesini gönderiyoruz. Tabi son olarak listeleme yapacağımız todoların kullanım durumu kaldı.
Onu da kısaca anlatmak gerekirse boş olan task listesi içerisinde initState içerisinde doldurma yapıyoruz.
Projeye basit todo ekleyerek sonucu ekranda gibi aldık ve herhangi bir problem çıkmadı. Umarım faydalı bir içerik olmuştur. Bu serinin devamı için olumlu olumsuz yorumlarınızı bekliyorum.
Herkese iyi kodlamalar...