MVVM Mimarisinde Dependency Injection Nasıl Kullanılır?

Erman Derici
Huawei Developers - Türkiye
5 min readNov 30, 2023
Şaşkın Droid

Giriş

Merhaba,

Bu makalede Dependency Injection nedir, neden kullanılmalı ve nasıl kullanılmalı beraber inceleyeceğiz.

Dependency Injection Nedir?

Dependency Injection temiz bir mimari için kullanılan tekniklerden biridir. Düzgün bir dependency injection kullanıldığında elde edilecek avantajlar arasında:

  • Refactoring kolaylığı
  • Test kolaylığı
  • Kodun tekrar kullanılabilirliği

bulunmaktadır. Peki dependency injectionu detaylı olarak açıklamak gerekirse nasıl açıklarız? Bir örnekle beraber inceleyelim.

Varsayalım ki elimizde bir araba var. Arabalar motor, pencereler, ana gövde gibi farklı parçalardan oluşur. Bu parçalar fabrikalarda üretilir, ama genellikle aynı fabrika yerine farklı fabrikalarda üretilip tek bir yerde montaj edilir. Tekerlek üreten bir fabrika aynı azamanda araba motoru da üretmez.

Tekerlek Üretim Örneği

Bu mantıkla kodumuzda bir araba sınıfı olduğunu düşünelim. Makaleyi kısa tutabilmek adına bu sınıfın içerisinde sadece motor olduğunu var sayacağım. Normalde şu şekilde yazılır:

Dependency Injection olmadan araba sınıfı

Bu yazılışın birkaç tane sorunu var. Car ve Engine sınıfları birbirleri ile sıkı bağlaşmış durumdalar. Farklı bir alt-sınıf veya implementasyon kullanmak istersek bize sıkıntı yaratacaktır.

Peki dependency injection bu sorunlara nasıl bir çözüm getiriyor? Dependency Injection için 2 yöntem vardır:

  • Constructor Injection
  • Field / Setter Injection

Constructor injection daha sık kullanılan yöntem olsa da setter injection kullanılması gereken bazı senaryolar da bulunmaktadır.

Constructor injection şu şekilde olur:

Constructor Dependency Injection olan araba sınıfı

Engine sınıfımızı Car sınıfının dışında oluşturarak parametre olarak verdik.

Setter injection ise şu şekilde olur:

Setter Dependency Injection olan araba sınıfı

Lateinit olarak belirttiğimiz Engine sınıfını Car sınıfını oluşturduktan sonra ana fonksiyonumuzun içerisinde Engine oluşturup Car sınıfı içerisindeki değişkene atıyoruz.

Dependency injection sayesinde Car sınıfımızı tekrardan farklı Engine implementasyonları ve alt-sınıfları ile kullanabiliyoruz. Çok basitçe ve özetle anlatmak gerekirse, dependency injection sınıfımızın içerisinde yeni sınıflar oluşturmak yerine bu sınıfları dışarıdan oluşturup sınıfın içerisine aktarmak diyebiliriz.

Bu örnekler ile dependency injection özünde nedir anlayabildiğimizi umuyorum, çünkü birazdan MVVM mimarisindeki bir uygulamada otomatik dependency injection nedir onu göreceğiz 😊

Smug Dog

Otomatik Dependency Injection

Günümüzde neredeye her şey için bir kütüphane ve dependency bulunuyor. Dependency Injection buna bir istisna değil. Android / Kotlin için Hilt kütüphanesi üstünden devam edeceğim.

Hilt Nedir?

Hilt, Dagger kütüphanesi üzerine geliştirilmiş boiler-plate dediğimiz sürekli tekrar eden kodların azaltılması ve yaşam döngüsüne dikkat ederek otomatik dependency injection yapan bir kütüphanedir.

Kök dizininde bulunan build.gradle dosyanıza alttaki satırı ekleyerek uygulamanıza eklemeye başlayabilirsiniz:

plugins {
...
id 'com.google.dagger.hilt.android' version '2.44' apply false
}

Sonraki adım olarak app klasörü içerisinde build.gradle dosyanıza alttaki blokları ekleyin:

...
plugins {
id 'kotlin-kapt'
id 'com.google.dagger.hilt.android'
}

android {
...
}

dependencies {
implementation "com.google.dagger:hilt-android:2.44"
kapt "com.google.dagger:hilt-compiler:2.44"
}

// Allow references to generated code
kapt {
correctErrorTypes true
}

Hilt Java 8 özelliklerini kullandığından dolayı Java 8'i etkin kılmayı unutmayalım. App klasöründeki build.gradle dosyası içerisine aşağıdaki bloğu ekleyin:

android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

Hilt Kullanımı

Hilt bütün uygulamaların @HiltAndroidApp olarak işaretlenmiş bir Application sınıfı bulundurmasını gerektiriyor:

@HiltAndroidApp
class ExampleApplication : Application() { ... }

Bu sınıfı oluşturduktan sonra diğer sınıflara geçebiliriz. Hilt’in desteklediği sınıflar şu şekilde:

  • Application (@HiltAndroidApp)
  • ViewModel(@HiltViewModel)
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

Eğer herhangi bir sınıfı @AndroidEntryPoint olarak işaretlersek bu sınıfa bağlı olan diğer sınıfları da işaretlememiz gerekmektedir. Örnek olarak işaretlenmiş bir Fragment’ı işaretlenmemiş bir Activity içerisinde kullanamayız.

Genellikle @Inject işaretini kullanarak bir sınıfın içerisine enjekte etmek istediğimiz sınıfmızı ekleyebiliriz:

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

@Inject lateinit var injectionTest: InjectionTestClass
...
}

Fakat bazı zamanlar constructor injection şeklinde kullanamayabiliriz:

class InjectionTestClass @Inject constructor(
private val service: InjectionTestService
) { ... }

Bunun sebebi ise Hilt InjectionTestService sınıfını nasıl oluşturacağını bilmesi gerektiğindendir. Kendimize ait olmayan (Üçüncü sınıf kütüphane sınıfları) ve Interface sınıfları bu şekilde oluşturulamaz. Bunun için Hilt’in bir özelliği olan Hilt Module kullanmamız gerekir.

Hilt Module

Hilt Modul dediğimiz sınıflar Hilt’in bazı sınıfların nasıl oluşturulması gerektiği gibi adımları ve bilgileri içeren sınıflardır. Direkt dependency injection kullanamadığımız durumlarda gerekli her bir class için ayrı ayrı yazılmaları gerekmektedir.

Bunun 2 yöntemi vardır:

  • @Provides işareti
  • @Binds işareti

@Provides örneği şu şekildedir:

@Module
@InstallIn(ActivityComponent::class)
object InjectionTestModule{

@Provides
fun provideInjectionService(): InjectionTestService{
return Retrofit.Builder()
.baseUrl("https://example.com")
.build()
.create(InjectionTestService::class.java)
}
}

@Binds örneği ise şu şekildedir:

@Module
@InstallIn(ActivityComponent::class)
abstract class InjectionTestModule{

@Binds
abstract fun bindInjectionService(
InjectionTestServiceImpl: InjectionTestServiceImpl
): InjectionTestService
}

İkisi arasındaki fark en basit özetiyle @Binds işareti bir Interface sınıfını bir implementasyona bağlamak için kullanılırken @Provides işareti üçüncü sınıf kütüphanelerin instance olarak oluşturulmasını sağlar.

Hilt’in ana özellikleri bu kadar. Makaleyi kısa tutmak adına atladığım birkaç tane adım var, daha detaylı bilgi için en altta referanslar kısmından linklere göz atabilirsiniz.

MVVM Uygulamada Hilt Kullanmak

Hilt’i nasıl kullanacağımızı öğrendiğimize göre artık MVVM yapısında bir uygulamaya göz atabiliriz.

Uygulamamızın yapısı şu şekilde:

  • Application Sınıfı
  • Activity or Fragment Sınıfları
  • ViewModel Sınıfları
  • Use Case Sınıfları
  • Repository / Implementation Sınıfları

Application sınıfımızı oluşturarak başlayalım:

Application Sınıfı

Sonrasında veri işlemlerini halletmek için repository sınıflarımızı oluşturalım ve Hilt modülünü yazalım.

İlk adım olarak Interface sınıfı:

Repository Interface

İkinci adım olarak implementasyon sınıfı:

Repository implementasyonu

Üçüncü adım olarak ise Hilt modülünü oluşturalım. Bu kısımda @Binds işaretini de kullanabilirsiniz:

Repository modülü

Firebase kullanıldığı için Firebase sınıflarının dependency injection ile enjekte edilebilmesi için modül sınıfını yazmamız gerekiyor:

Firebase modülü

Bir sonraki adım olarak use case sınıflarımızı oluşturalım. Bu sınıflar repository sınıfları içerisinde yazdığımız metodları teker teker çağıran sınıflardır:

Use Case
Use Case Module

Use case sınıflarını bitirdikten sonra viewmodel sınıflarına başlayabiliriz. Yazdığımız bu use case sınıflarını viewmodel içerisinde çağırıcağız:

View Model

Sonuç

Bu makalede dependency injection nedir, dependency injection yöntemleri, Hilt nedir ve nasıl kullanılır ve MVVM yapısında bir uygulamada Hilt nasıl kullanılır konularını beraber inceledik.

Bu şekilde uygulamanızı kolayca refactor edebilirsiniz. Örnek olarak Firebase kullanmak yerine Huawei Cloud DB’ye taşınmak isterseniz yapmanız gereken tek şey repository sınıflarını ve belki de model sınıflarınızı değiştirmeniz gerekiyor olucak. Refactor işlemi kolay ve basite indirgeniyor.

Epeyce uzun bir makale oldu, eğer sonuna kadar okuduysanız desteğiniz için çok teşekkür ediyorum. Benim için desteğiniz değerli.

Cat Wiggle

Referanslar

--

--