Android MVVM / Model-View-ViewModel

Murat Yaman
Huawei Developers - Türkiye
6 min readMay 28, 2020

Sürdürülebilir, test edilebilir, Hızlı geliştirilebilir bir android uygulaması nasıl oluşturabiliriz? Sorusundan yola çıkarak Seperation Of Concerns presibini ögrenmemiz gerektigini anladık.

SoC (Separation Of Concerns) Nedir?

yazılımda işlev ve özelliklerine göre programlama kodlarının (class, fonksiyon vb.) birbirinden ayrılması gerektiğini belirten bir tasarım prensibidir ve günümüzde tercih edilen pek çok yazılım tasarım şablonunun (design pattern) da temelini oluşturur.

Her eleman (modül) diğerinden bağımsızdır ve kendi sorumluluğuna (single responsibility) sahiptir. Bu kapsamlar sınırlarla belirlenir.

Yazılımın geliştirme sürecine dair kullanılan “sınır” kavramı oldukça net bir çizgi çizer, sorumluluklar sınırlarla tanımlanır ve diğerinden ayrıştırılır.

Tüm bu kavramlar içerisinde SoC süreci mümkün olan en küçük parçaya (işlev ve sorumluluk kümesi bağlamında) bölmeyi ve ortaya çıkan sorumlulukları bağımsız kılmayı öğütler.

Bu sayede diğer elemanların işleyişi aksamadan geliştirme yapmak mümkün hale gelecek, olası bir sorunda diğer elemanlar sorundan tanımlanan sınırlar çerçevesinde etkilenecektir.

  • Yüksek kod kalitesi saglar. (yazdıgımız kod spagetti kod olmaktan çıkar.)
  • Test edilebilir kod saglar.
  • Hızlı bir geliştirme imkanı saglar.

MVC, MVP, MVVM,… Mimari patternlarını kullanarak başlayabiliriz.

Aslında mimari desenlerin tamamında yukarda yazdıgımız kod kalitesi, test edilebilir kod ve hızlı geliştirme imkanı saglamaya çalışır burada MVVM bu işi digerlerinden daha iyi yapar.

MVVM

Datanın güncelenmesi durumunda UI i başarılı bir şekilde günceller ve en önemlisi View in herhangi bir nesnesi ViewModel tarafında tutulmaz. ViewModel View hakkında herhangi bir bilgi sahibi olmadıgı için ViewModeli patlatmadan View’i rahatça test edebiliriz.

MVVM Android geliştirme için en iyi seçeneklerden biridir. Google tarafından tam olarak destekleniyor ve teşvik ediliyor. Bu yazıda MVVM’nin gerçekte ne olduğu hakkında bir fikriniz olması için bilmeniz gereken her şeyi öğreneceksiniz.

Aslında teoriyi her zaman bir çok insan için sıkıcı olabiliyor ama gerçek kodlamaya geçmeden önce bunun ne oldgunu bilmek önemlidir.

View

Kullanıcının ekranda gördükleri, View yalnızca kullanıcıyla olan etkişimleri ele alır button tıklanması veya kullanıcıya herhangi bir datayı göstermede kullanıcı hareketlerini ViewModel’ göndererir. UI olarak gördügünüz her şey bu katmandadır Acitivity,Fragment . View kullanıcı etkilşimini ViewModel’ a gönderir veya ViewModel de bulunan liveDatayı dinleyerek gelen data ile UI daki gösterim işlerini yapar.

View için de uygulama içindeki bir veritabanı iltişim kurmak gibi herhangi bir iş mantıgı koymayın. View sadece isteklerini ViewModel’a bildirir ve ViewModel’ i dinler.

ViewModel

Model’den gereken dataları alır UI’ya uygular yani ekrana sunar. Observable datayı kullanır. ViewModel’ de MutableLiveData assign ederiz çünkü MutableLiveData sayesinde UI içindeki tüm degişiklikler bu degişkene direk atanır.

Şemaya bakıldıgında ViewModel’e doğru yalnızca bir yönde işaret ediyor. Bu, ViewModel’in hangi View’ ın onu kullandığı hakkında hiçbir fikri olmadığı anlamına gelir. ViewModel’in View’a hangi verilerin görüntüleneceğini söylemesi gerekir.

Buradaki önemli nokta, ViewModel’deki uygun verileri gözlemlenebilir hale getirmektir. Bunu yaparak, veri değiştiğinde View’ i doğrudan ViewModel’den güncelleme ihtiyacından kurtuluruz.

Bir View’ın zaten ViewModel referansı vardır, bu nedenle ViewModel’in gösterdiği bazı verileri kolayca gözlemleyebilir. Veriler değiştiğinde, gözlemleyen tüm Viewlar bu değişiklik hakkında bilgilendirilecektir.

Bu, gözlemlenebilirler oluşturmak için LiveData ile yapılabilir. Avantajlarından biri, etkinliği veya parçası zaten yok edilmişse gözlemciye otomatik olarak bildirimde bulunmaması ve sizi yaşam döngüsünü kendiniz yönetmekten kurtarmanızdır.

Model

Data’nın kaynağını oluşturur. Viewmodel ve View, bu datayı kulanır. Model, observable olmalıdır. En basit şekilde bir modelin observable olması, dinlenilen bir objenin veya degişkenin değişmesi durumunda ilgili yerlere son durum hakkında bilgi yollanmasıdır.

Model, business’a özel tüm kodu koyduğunuz yerdir.

Teknik olarak ViewModel ve Model arasında Repository biçiminde bir ara adım olsa da, Repository ’den aşağıya doğru her şeyi kullanıcı arabiriminden uzakta kendi sınıfları grubu olarak kabul edebilirsiniz.

Bunlar uygulamanızın verileri üzerinde çalışır ve local veritabanından veya ağdan alır.

Repository’nin local depolama ve sunucu arasında arabulucu olarak özel bir rolü vardır. Burası, uzak verilerin yerel olarak önbelleğe alınıp alınmayacağını kontrol ettiğiniz yerdir.

ViewModel bazı veriler istediğinde, verileri Repository’den alır. Sonra ne yapacağınıza karar vermek repository’ye bağlıdır.

ViewModelFactory

ViewModel nesnelerini diğer classlara sağlamak için ViewModelFactory adında bir sınıf oluşturulur.

Constructor parametre olarak apiden dataları bize sağlayacak sınıf olan Repository sınıfını parametre olarak alır. ViewModel sınıfının nesnesi, factory içinde oluşturulur.

Pattern AntiPattern

  • ViewModel içerisinde hiçbir şekilde Android paketini import etmememiz gerekiyor.
  • View i hiç bir şekilde ViewModel’a paslamayın leak oluşabilir. Scope ları birbirinden farklıdır.

ViewModelProvider context bazlı eğer o view modeli daha önce çağırmışsa bir daha üretmiyor önceden oluşturduğunu veriyor.

MVVM bileşenleri arasında haberleşme

Yalnızca View, ViewModel’deki verileri gözlemlemez, aynı zamanda ViewModel, Repository’deki verileri de gözlemler; bu da local veritabanından ve uzak veri kaynağından gelen verileri gözlemler.

Bağlantıları aşağıdaki şekilde düşünebilirsiniz.

Hiyerarşiden aşağı doğru inerken, üst sınıfın çocuğuna doğrudan bir referansı vardır. Öte yandan, çocuğun ebeveynine bir referansı yoktur. Çocuklar bazı verileri yalnızca LiveData veya başka herhangi bir kütüphane aracılığıyla gözlemlemelerine izin vererek açığa çıkarırlar.

Daha iyi bir hayal gücü için aşağıdaki ok dağınık diyagramına bir göz atın. Sizi başlangıçta gereksiz dağınıklıktan kurtarmak istedim, bu yüzden bu gözlemlenebilir oklar MVVM’yi gösteren ilk diyagramda yoktu.
Burada bahsettiğimiz son önemli şey, her zaman yukarıdaki referans ağacına uymanız gerektiğidir.

Örneğin, ViewModel’inizi Repository’yi atlarken doğrudan veritabanından veri almayın! Her şeyin amacı vardır ve kodu modüler, bakımı kolay ve okunması güzel hale getirir. Kodunuzu yazdığınızdan çok daha fazla okuyacaksınız, bu nedenle okunabilirliği bir numaralı öncelik haline getirin.

RxJava

RxJava da ReactiveX’den türetilmiş Java için kullanabileceğiniz ve en temelde observable pattern üzerine kurulu asenkron işlemler için kullanılan güçlü bir kütüphanedir . Kendi içinde 3 parçaya ayrılır

Observable (Gözlenen) — Observer (Gözlemci) — Datayı işleyen metodlar

Observable : Veriyi dışa aktaran yapıdır.

Observer : Observable tarafından dışa aktarılan veriyi dinleyen yapıdır.

Observer ,Observable’ı dinleyerek Observable tarafından aktarılan veriyi alır.

Lifecycle-aware Components

Lifecycle-aware Components, activity veya fragment gibi diğer bileşenlerin yaşam döngüsünün farkında olan ve bu bileşenin yaşam döngüsü durumundaki değişikliğe yanıt olarak bazı eylemler gerçekleştiren bir bileşendir.

LifecycleObserver yaşam döngüsünü gözlemler ve buna göre eylemleri gerçekleştirir.Böylece LifecycleObserver, LifeCycleOwner’ın yaşam döngüsünü gözlemler ve işlemi gerçekleştirir.

LiveData

Temel olarak datadaki değişiklikleri izlememizi sağlayan observable bir data holderdır. Data değişikliklerindeki bizi notify eder, böylece ui’ı değiştirebiliriz.

LiveData LifeCycle aware bir componentdir. Aslında en önemli özelliği de burada karşımıza çıkıyor. Çünkü daha önce benzeri geliştirmeler yaptığımızda alabileceğimiz crashlerin Android’in kendisi tarafından handle edilmesini sağlıyor. Şöyle özetleyebiliriz; Livedata activity’nizin ekranda mı, değil mi yoksa tamamen destroy mu olduğunu bilir ve updateleri buna göre gönderir. Bunun için ise iki interface vardır. Biri lifecycle owners, activity’ler, fragmentler; diğeri ise livecycle observers, livecycle owner’ı izleyip, lifecycle observersları notifiy eder. UI componentleri LiveData’yı, LiveData da LifeCycleOwner’ları observe eder.

LiveData, gözlemlenebilir bir veri tutma sınıfıdır.

Aynı zamanda Observable(Dinlenebilir) içindeki tuttugu data değiştiği zaman bundan haberdar oluruz. Activitiy kullanıcı tarafında kill edilirse kendisini clear etmemize gerek yok kendisini temizliyor zaten.

LifeCycle-Aware dir Activity veya Fragment gibi bileşenlerin yaşam döngülerine karşılık hareket edebilir.

LiveData Observer sınıfından türetilen bir observer ın aktif yaşam döngüsünde olduğunu varsayar. Yani LifeCycle state inin STARTED yada RESUMED olduğu durumlarda bu observer’ı güncellemelerden haberdar eder. Bahsedilen bu observer LifeCycleOwner arayüzünü implemente eden bir nesne ile eşleştirilerek kayıt edilebilir. Bu durum sayesinde LifeCycleOwner olan componentın state i DESTROY olduğu zaman observer ile LifeCycleOwner’a sahip olan componentin arasındaki bağın kalkmasını sağlar. Yani örneğin bir Activity’de LiveData’nın değişikli gözlemleyen bir Observer varsa, Activity destroy olduğu zaman bu değişikliği gözlemleyen bağ da ortadan kaldırılır.

Memory Leak : Observer lar LifeCycle nesnelerine bağlıdır ve bağlı oldukları Componentler DESTROY olurlarsa otomatik olarak temizleme işlerini kendileri yaparlar.

Güncel veri : Eğer yaşam döngüsü inaktif durumda olsa bile, bu yaşam döngüsü aktif olana kadar en son kaydedilen veri kullanılır.

Rotaion degişimleri: Eğer bir activity ya da fragment cihazın portrait mode dan landscape mode çevrilmesi gibi bir konfigürasyon değişikliğinden dolayı yeniden oluşturulursa, en son kaydedilen veriler saklanır.

Biliyorum biraz uzun oldu ama anlaşılması gereken bir konu.

Sabredip buraya kadar okuduğunuz için teşekkür ederim. 🙂👏💪

--

--