Android Örnekleri #2 - Dependency Injection - Koin Kütüphanesi Kullanımı - #2

Android dependency injection - Koin kütüphanesi kullanımı - 2

Koin kullanımı serisi ilk yazısına buradan ulaşabilirsiniz.

Koin kütüphanesi kullanımı serisinin 2. bölümü ile devam ediyoruz.

Bu yazıda Koin'i; viewmodel entegrasyonu, Koin module unit testi gibi konular ile detaylandıracağız.

Öncelikle app build.gradle dosyasına Koin kütüphanesini ekliyoruz.

dependencies {

    def koinVersion = "2.1.5"

    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.13'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    // Koin
    implementation "org.koin:koin-android:$koinVersion"
    implementation "org.koin:koin-androidx-scope:$koinVersion"
    implementation "org.koin:koin-androidx-viewmodel:$koinVersion"
    implementation "org.koin:koin-androidx-fragment:$koinVersion"
    testImplementation "org.koin:koin-test:$koinVersion"
}
build.gradle

MainViewModel class'ını oluşturalım.

class MainViewModel : ViewModel() {

    val helloText = "Hello Koin"
}
MainViewModel

Şimdi di package'ı altına mainModule kotlin file'ı oluşturalım. Bu dosyada MainActivity'i çalıştırmak için gerekli objeleri oluşturacağız. (MainViewModel gibi)

di.MainModule:

import com.emreakcadag.koinexample.MainViewModel
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module

/**
 * Created by Emre Akçadağ on 16.06.2020
 */

val mainModule = module {
    // Bu şekilde isimlendirilmiş instance'lar da oluşturabiliyoruz.
    single(named("APP_NAME")) { "Koin Example" }

    // ViewModel sınıfları viewModel scope'u içinde tanımlıyoruz.
    viewModel { MainViewModel() }
}
MainViewModel

MainViewModel'i viewModel scope'u içinde yarattık. bu kullanım sadece viewModel sınıfları için geçerlidir.

MyApplication class'ı son hali:

class MyApplication: Application() {

    override fun onCreate() {
        super.onCreate()

        startKoin {
            // Debug level'da loglaması için Level.DEBUG parametresi geçtik.
            androidLogger(Level.DEBUG)
            androidContext(this@MyApplication)

            // buraya farklı paketler için de (networkModule vs) oluşturduğunuz modulleri eklemeniz gerek.
            modules(listOf(mainModule))
        }
    }
}
MyApplication
MyApplication sınıfını AndroidManifest.xml'de application tag'ine name attribute olarak vermek gerekiyor. Yoksa koin başlayamayacağı için uygulama kendini kill eder.
... android:name=".MyApplication" ...
AndroidManifest.xml

Şimdi viewModel'i activity'de inject edebiliriz. MainActivity:

class MainActivity : AppCompatActivity() {

    private val mainViewModel: MainViewModel by viewModel()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runOnUiThread { // Bu örnek için optional.
            textView.text = mainViewModel.helloText
        }
    }
}
MainActivity

MainActivity içinde by viewModel() ile MainViewModel'i inject ettik.
Artık normal obje -MainViewModel()- oluşturmuş gibi kullanabiliriz.

Koin Unit Test

MainModuleTest sınıfını KoinTest sınıfından extend edip, @Test fonksiyonlarını aşağıdaki gibi yazıyoruz.

import com.emreakcadag.koinexample.di.mainModule
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertTrue
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.koin.core.context.startKoin
import org.koin.core.context.stopKoin
import org.koin.core.qualifier.named
import org.koin.test.KoinTest
import org.koin.test.get
import org.koin.test.inject

/**
 * Created by Emre Akçadağ on 16.06.2020
 */
class MainModuleTest : KoinTest {

    private val appName: String by lazy { get<String>(named("APP_NAME")) }

    // Test için inject kullandık.
    private val mainViewModel: MainViewModel by inject()

    // Class çalıştığında ilk gireceği fonksiyon
    @Before
    fun setup() {
        startKoin {
            modules(listOf(mainModule))
        }
    }

    // Class çalıştığında son gireceği fonksiyon
    @After
    fun koinStop() {
        stopKoin()
    }

    @Test
    fun `Test APP_NAME Created`() {
        assertTrue(appName == "Koin Example")
    }

    @Test
    fun `Test MainViewModel Created`() {
        assertNotNull(mainViewModel)
    }
}
MainModuleTest

Yazının sonuna gelirken; Koin kütüphanesi orta ve küçük ölçekli uygulamalar için uygun ancak daha büyük projeler için kullanılmasını pek tavsiye etmiyorum.
Büyük projeler için Dagger2 veya Google'in yeni Dependency Injection kütüphanesi Hilt çok daha sağlıklı olacaktır.

İlerleyen günlerde yeni bir seri ile Hilt kütüphanesini örneklendirmeye çalışırım :)

Kaynak kod: github.com/emreakcadag/koin-example
Sorularınızı ve isteklerinizi yorum bölümünden iletebilirsiniz.
Kaynak:
Bu postu paylaş:

0 yorum

Yorum yapmak için giriş yapmanız gerekmektedir. Giriş yap
Henüz hesabınız yoksa 20 saniyenizi ayırıp kayıt olabilirsiniz. Kaydol