Flutter’da Bloc ile Counter Uygulaması Geliştirmek

Berat Göktuğ Özdemir
Flutter Türkiye
Published in
6 min readJul 17, 2021

--

Eminim ki daha önce BLoC adını pek çok kez duymuşsunuzdur. Bununla ilgili bir eğitim serisi bile var. İşte bu serinin 3. videosunu yazılı olarak buradan takip edebilirsiniz.

Yazı uzun görünebilir. Her şeyi detaylarıyla beraber aktarmaya çalıştım. Yazıyı mutlaka tek seferde okumaya çalışın.

Bloc ismi biraz korkutucu geliyor olabilir ancak korkulacak bir şey olmadığını birazdan göreceksiniz.

Bloc (Business Logic Component), bana Türkçe konuş derseniz “İş Mantığı Bileşeni”,

tarafından geliştirilmiş bir State Management kütüphanesidir.

Bu kütüphane, basitçe, Kullanıcı Arayüzünü (UI), İş Mantığından (Business Logic) ayırmanıza yardımcı olur. Bu sayede, hem kodunuz daha okunaklı olur hem de test edilebilirliği ve yeniden kullanılabilirliği kolaylaşır.

Neden State Management Kütüphanelerinden Faydalanmalıyız?

State Management (Durum Yönetimi), uygulama ile ekran bazında kompleks bilgi değişikliklerini ve bilgi paylaşımını yaparken bize yardımcı olur.

Bunlara ek olarak, setState ile yapamayacağınız bazı işlemleri gerçekleştirmenize yardımcı olur. Burada bazılarından bahsettim.

Hadi başlayalım!

Bloc Eklentileri

Bloc ile çalışırken size yardımcı olacak iki adet eklenti var.

Eğer VSCode kullanıyorsanız bunu, IntelliJ veya Android Studio kullanyorsanız bunu indirebilirsiniz.

Kullanacağımız Paketler

Yapacağımız uygulamada kullanacağımız iki paket var.

Bu iki paket “kuru fasulye - pilav”, “simit - çay” gibi ayrılmaz ikililerden biri.

Başka bir yazıda ve videoda bahsedeceğim ama kısaca neden Equatable kullandığımıza da bahsedeyim.

Neden Equatable paketini kullanıyoruz?

Flutter iki nesneyi kıyaslarken, “Aaa. Bunların ikisi de kırmızı kitap. Öyleyse bunlar aynı kitap!” şeklinde düşünmüyor. Bunun yerine bunların Hash Koduna bakıyor. Burada detaylıca inceleyebilirsiniz.

Bunu tabi ki bir paket kullanmadan yapabilirsiniz ama başka bir yazıda bahseceğim.

Equatable paketi sayesinde, karşılaştırılmasını istediğiniz alanları belirtiyorsunuz. Geri kalan işi sizin yerinize Equatable yapıyor.

“Peki ama Hash Code ne?” diye merak ediyorsanız, bir objenin kimliği olarak düşünülebilir. Her objenin bir kimliği yani hashCode’u vardır. Karşılaştırılarken de bu kimliğine göre karşılaştırılır.

Şimdi yeni bir Flutter projesi oluşturun ve beni takip edin.

Bu yazı Flutter 2.2.3 ve Null Safety kullanılarak oluşturuldu. Bunu göz önünde bulundurarak benimle beraber devam edebilirsiniz.

Pubspec.yaml dosyasının düzenlenmesi

Equatable ve Flutter Bloc paketlerini dependencies altına ekleyin.

Benimle aynı sürümü kullanmaya dikkat edin. İleriki sürümlerde bazı Widget ve Metotlar kullanım dışı kalmış olabilir. Eğer isterseniz, uygulama bittikten sonra kendi başınıza son sürümleri ile baştan yapabilirsiniz.

/pubspec.yaml

Bloc klasörünün oluşturulması ve düzenlenmesi

Bloc klasörünü ve içindeki dosyaları isterseniz tek tek elle oluşturabilirsiniz.

Ya da benim gibi yazının başında bahsettiğim eklentiden faydalanabilirsiniz.

lib klasörüne sağ tıklayın ve Bloc: New Bloc butonuna basın.

Karşınıza gelen ekrana Bloc’unuzun ismini yazın. Bizim örneğimiz için bu isim counter.

Ekranın sağ alt köşesinde başarıyla oluşturulduğuna dair bir mesaj göreceksiniz.

Yoksa sizde oluşmadı mı? Hala lib klasörü boş mu?

Eğer sizde de bir şey oluşmadıysa boşuna zorlamayın ve Bloc kullanmayı bırakın. Şaka şaka. Aslında oluştu ama yenilemek gerekiyor. Görselde sağ üste gördüğünüz Refresh butonuna sakince basın. Yazı uzun olunca böyle harika şakalar olabiliyor.

Sanırım artık kod yazmaya hazırız. Gelin counter_state.dart ile başlayalım.

Counter State dosyasının düzenlenmesi

Önce biraz State’den bahsedelim.

State bizim belirlediğimiz bir alan içerisinde (ben genelde buna havuz diyorum), yani BlocProvider’ın altındaki alan içerisinde erişebildiğimiz ve bloc’umuzun durum bilgilerini tuttuğumuz sınıf.

Genelde her bir durum için ayrı sınıf olur ve ana bir sınıftan türetilir.

Başlangıç durumu için Initial, işlem yapılırken InProgress, bir hata varsa Error ve işlem tamamlandıysa Done/Success gibi isimlerle oluşturulabilir.

Her bir durum içerisinde gerekli olan veriler tutulur. Örneğin, Error State’i içerisinde Exception tutulabilir.

CounterInitial ile bir işimiz olmayacak. İsterseniz, biraz düzenleyelim.

/lib/bloc/counter_state.dart

value içerisinde sayacımızın değerini tutacağız. Props içerisinde value değerini vererek, karşılaştırma yapılırken value değerine göre karşılaştırılmasını istediğimizi belirtiyoruz.

Counter Event dosyasınının düzenlenmesi

Eventler, gerçekleşebilecek eylemleri ifade eder. Bizim uygulamamız için gerekli eventler sayacın arttırılması ve azaltması.

Önerilen isimlendirme kuralı:

Bloc Adı + Event (Geçmiş Zaman)

Yani, CounterIncremented ve CounterDecremented.

Bahsettiklerime bağlı olarak gelin eventlerimizi düzenleyelim.

/lib/bloc/counter_event.dart

Gördüğünüz gibi Arttırmak ve Azaltmak için ayrı eventlerimiz var. Bu eventler esnasında bir değer almadığımız için içerisine bir şey yapmamıza gerek yok.

Ama arttırma sırasına kaçar kaçar arttırılmasını kullanıdan isteyecekseniz eventlere değişken olarak ekleyebilirsiniz. Props içerisine bu değişkenlerden bahsetmeyi tabi ki unutmayın :)

Eventlerimiz de hazır olduğuna göre bloc dosyasına geçebiliriz.

Counter Bloc dosyasının düzenlenmesi

Bloc dosyası, logic kısmının bulunduğu bölüm.

Burada başlangıç durumundaki state’i ve hangi event geldiğinde ne yapılacağını belirtiriz.

Muhtemelen, şu an sizin counter_bloc.dart dosyanız size kızıyor. Çünkü CounterInitial diye bir şey olmadığını farketti ve oldukça sinirlendi. Korkmayın. Bana da kızgın. İsterseniz gelin biraz yumuşatalım.

CounterInitial yerine CounterState yazarak başlayabiliriz. Bu sefer de CounterState mi kızdı? Bizden sayacımızın başlangıç değerini, yani state içerisinde value değişkeninin başlangıç değerini, istiyor. Sayacımızı sıfırdan başlatmak istiyorsak kocaman bir 0 yazabiliriz.

/lib/bloc/counter_bloc.dart

mapEventToState metodu, az evvel bahsettiğim beyin kısmı. Şu event geldiğinde şunu yap diye öğrettiğimiz kısım.

Elimizde iki adet event var. İsterseniz bunları kendisine tanıtalım.

/lib/bloc/counter_bloc.dart

Şu an eventleri biliyor ama ne yapması gerektiğini bilmiyor.

Burada yapılacak tek şey sayacının değerini bir arttırmak veya azaltmak. Yeni değerimizi de kendisi gibi yeni bir state ile geriye döndürmek.

Bloc içerisinde Stream (akış) kullanılır. Stream, asenkron olaylar dizisidir.

Geriye bir şey döndürürken return ifadesi değil yield ifadesini kullanmamız gerekiyor.

Biraz karışık mı geldi? Aslında değil. Kodu görünce daha iyi anlayacaksınız.

Bloc içerisinde state diyerek mevcut state’imize erişebiliriz.

Sakın state.value++ veya state.value = state.value + 1 gibi bir şey yapmaya kalkmayın. Çünkü yapamazsınız. State’imiz içerisindeki value final olduğu için değiştiremezsiniz.

Buraya kadar gerçekten büyük yol katettiniz.

  • Equatable paketini öğrendiniz.
  • State’ler nedir ve nasıl olmalı öğrendiniz.
  • Event’ler nedir ve nasıl olmalı öğrendiniz.
  • Bloc yapınızı düzenlemeyi öğrendiniz.

Kendinizi küçümsemeyin. Büyük iş başardınız. Ancak henüz tebrik etmek için erken. Bu yazdıklarımızı hala bir yerde kullanmıyoruz. Gidelim ve UI’ımıza patronun kim olduğunu öğretelim.

Counter Bloc havuzumuzu oluşturalım

Counter Bloc’umuza erişeceğimiz alanı belirlememiz gerekiyor.

Bizim sayaç bilgilerine MyHomePage içerisinde ihtiyacımız olduğu için isterseniz BlocProvider’ı bunun hemen dışına ekleyelim.

/lib/main.dart

Create parametresi içerisinde oluşturacağımız Bloc nesnesini belirtiyoruz. Bu aşamadan sonra flutter_bloc paketini ve counter_bloc.dart dosyanızı import etmeyi unutmayın.

Bloc Provider’ı oluşturmak için kısayol kullanabilirsiniz. MyHomePage e dokunun. Çıkan ampule tıklayın ve Wrap with BlocProvider’ı seçin.

Artık, MyHomePage ve altında CounterBloc’a erişebiliriz.

UI’a hükmedelim!

Stateful Widget’a da ihtiyacımız kalmadı. İsterseniz, Stateless Widget’a çevirip, _counter değişkeninden ve _incrementCounter metodundan kurtulabiliriz.

/lib/main.dart

Şimdi, FloatingActionButton içerisinde arttırma işlemini gerçekleştirelim.

İki farklı şekilde mevcut bloc’a erişebiliriz.

BlocProvider.of() kalıbı daha önce provider kullanmışlara tanıdık gelebilir. Aslında çok da şaşıracak bir şey yok çünkü Bloc’da kendi içerisinde Provider kullanıyor :)

context.read() yazımı daha kısa ve daha yaygın. O yüzden ben context.read i tercih ediyorum. Bu noktada dikkat etmeniz gereken en önemli şey context.read(), flutter_bloc paketi ile geliyor. Dolayısıyla, kullanacağınız yerlerde önceden import etmeyi unutmayın.

Bloc içerisinde doğrudan metodu çağırmayız. .add() diyerek eventimizi ekleriz. Ekler eklemez bloc’umuz gerekli işlemleri yapmaya başlar.

Peki, counter değerini nasıl göstereceğiz?

Bunun için de kullanabileceğimiz birkaç yöntem var. Ben size ikisini göstereyim. Üçüncüyü siz tahmin edin :)

context.watch(), isminde de anlaşıldığı gibi, context.read()’den farklı olarak değişiklikleri dinler ve değişiklik gerçekleştiğinde kendini günceller.

Ancak, okunabilirliği biraz olumsuz etkilediği için tavsiyem bunun yerine BlocBuilder kullanmanız. Elbette bunu oluşturmak için de eklentimizden faydalanabiliriz.

Sonrasında Sırasıyla Bloc Adını, State Adını yazmak ve Text içerisinde state.value değerini göndermek kalıyor.

Vay canına. Oldukça uzun bir yazı oldu ve hala okuyorsun. Gerçekten hayran kaldım. O zaman bu çabanı taçlandıralım.

Sayacı azaltma ve değeri AppBar içerisinde gösterme kısımlarını sen yap. Eğer bir sorun yaşarsan bana ulaşmaktan da lütfen çekinme.

Bu seriyi YouTube üzerinden takip edebileceğini unutma!

Bana aşağıdaki bağlantılardan ulaşabilirsin.

Twitter: bgoktugozdemir

GitHub: bgoktugozdemir

LinkedIn: bgoktugozdemir

Eğer kodlara gist olarak erişmek isterseniz aşağıdan erişebilirsiniz.

--

--