
Android Programlamada Jetpack Compose ile MVVM Mimarisi

MVVM Nedir ?
MVVM ( Model-View-ViewModel) modern Android Programlama’da kullanılan bir mimari desendir. Mimari desenler bize daha temiz kod yazma,kodun okunabilirliğini arttırma,kodun sürdürülebilir ve geliştirmeye açık olması açısından büyük fayda sağlar.
MVVM’i etkili bir şekilde kullanmanın anahtarı, uygulama kodunun doğru sınıflara nasıl yerleştirileceğini ve sınıfların nasıl etkileşime gireceğini anlamakta yatar.
- View: UI kodunu (Activity, Fragment, Jetpack Compose), XML’i içerir. Kullanıcı eylemlerini ViewModel’e gönderir ancak cevabı doğrudan almaz. Cevabı almak için, ViewModel’in ona sunduğu observable’ları kullanması gerekir.
- Not: Jetpack Compose ile UI, deklaratif bir yapıya sahip olduğundan, ViewModel’den gelen veri değişiklikleri otomatik olarak UI bileşenlerine yansır, böylece daha dinamik bir kullanıcı arayüzü oluşturulabilir.
- Model: Uygulamanın verilerini ve iş mantığını temsil eder. Model ve ViewModel yapıları veri almak ve kaydetmek için birlikte çalışırlar.
- ViewModel: View ile Model arasında bağlantı kurmayı sağlar.ViewModel hangi View’ı kullanması gerektiğini bilmez çünkü View ile doğrudan bir bağlantısı yoktur. Bu nedenle, ViewModel, etkileşimde olduğu view’dan haberdar değildir.
MVVM’in Avantajları ve Dezavantajları
Avantajları | Dezavantajları |
Test etmesi ve bakımı kolaydır. | Basit projeler için karmaşık olabilir. |
Ölçeklenebilirliği sayesinde kodda kolayca geliştirme yapılabilir. | Hata ayıklama sürecinde imperaktif (geleneksel) koda göre zor olabilir. |
Sürdürülebilir bir yapıya sahiptir. |
Basit bir şekilde MVVM pattern’ini bir proje üstünden örnekleyelim.
Örnek MVVM Mimarisi
Projemizin Model katmanında veri tiplerinin ve değişkenlerin yer aldığı bir data class ile kullanıcı verilerini almak için kullandığımız özellikle API kullanımında işimizi kolaylaştıran bir repository class’ımız yer almaktadır.
data class UserData(
var name : String,
var age : Int,
)class UserRepository {
suspend fun fetchUserData(): UserData{delay(2000)
return UserData("Mary",22)
}
}
Not: Projenizde API kullanmaya karar verdiyseniz mutlaka Retrofit ve Dagger Hilt kullanmaya özen gösterin.Bu sayede verileri yönetmeniz kolaylaşacaktır.
Şimdi gelelim ViewModel katmanında yer alan HomeViewModel class’ına;
class HomeViewModel : ViewModel() {
val userRepository : UserRepository = UserRepository()
private val _userData = MutableLiveData<UserData>()
val userData : LiveData<UserData> = _userDataprivate val _isLoading = MutableLiveData<Boolean> (false)
val isLoading : LiveData<Boolean> = _isLoadingfun getUserData(){
viewModelScope.launch {
val userResult = userRepository.fetchUserData()
_userData.postValue(userResult)
_isLoading.postValue(false)
}
}
}
- Burada viewModelScope.launchiçinde asenkron bir işlem başlatır ve UI bloklanmaz.
- Model katmanında oluşturduğumuz UserRepository classındaki fetchUserData()fonksiyonu ile kullanıcı verisi alınır.
- postValueile Coroutine içinde arka planda çalışırken, LiveData değerini Main Thread’e güvenli bir şekilde iletiyoruz.
- View katmanında Jetpack Compose ile bir UI görünümü elde ediyoruz.
@Composable
fun HomePage(modifier: Modifier = Modifier, viewModel: HomeViewModel) {val userData = viewModel.userData.observeAsState()
val isLoading = viewModel.isLoading.observeAsState()
Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(onClick = {
viewModel.getUserData()}) { Text(text = "Get Data") }
if (isLoading.value == true) {
CircularProgressIndicator()
} else {
userData.value?.name?.let {
Text(text = "Name: $it")
}
userData.value?.age?.let {
Text(text = "Age: $it")
}
}
}
}
HomePage fonksiyonu ViewModel’dan gelen veriyi dinler ve UI’ı günceller.Kullanıcı Get Data butonuna tıklayınca, viewModel.getUserData() çağrılır ve veri getirilmeye başlanır.
Yüklenme durumu (isLoading) true olur ve ekrana CircularProgressIndicator gelir.2 saniyelik gecikmeden (delay(2000)) sonra veriler UI’a aktarılır ve yüklenme durumu false olur.
Burada gördüğünüz üzere UI sadece ViewModel’i izler ve değişikliklere otomatik yanıt verir.