Android Injection : Simple Example (Dagger 2 — Hilt — Koin) : 1/2

Mohammed Kadi

--

Photo by Denny Müller on Unsplash

I write simple project for compare Android injection in (Dagger 2 — Hilt — Koin) of this cases :

  • class with constructor
  • class with constructor (With Parameter)
  • SharedPreference
  • Sqlite
  • ViewModel
  • Room
  • Room : RecyclerView

The source code of application :

DEPENDENCY INJECTION

Casr Depende on Engine
Engine Dependense of Car

Setup

Dagger 2

in build.gradle of your app module add :

in plugins section :

// in plugins section
// Dagger 2 with kotlin
// room
id 'kotlin-kapt'

in dependencies section :

// in dependencies section
// Dagger 2
implementation 'com.google.dagger:dagger:2.31.2'
annotationProcessor 'com.google.dagger:dagger-compiler:2.31.2'
// Dagger 2 with kotlin
kapt 'com.google.dagger:dagger-compiler:2.31.2'

Hilt

in build.gradle of your root project add :

//dagger:hilt
classpath "com.google.dagger:hilt-android-gradle-plugin:2.31-alpha"

in build.gradle of your app module add :

in plugins section :

//dagger:hilt
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'

in dependencies section :

//dagger:hilt
implementation 'com.google.dagger:hilt-android:2.31-alpha'
kapt 'com.google.dagger:hilt-android-compiler:2.31-alpha'
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'

Koin

in build.gradle of your app module add :

//koin
implementation "org.koin:koin-android-viewmodel:2.1.6"
implementation "org.koin:koin-android:2.1.6"

Inject : Constructors

Dagger 2

Class with inject constructor

class Car2 @Inject constructor(){

Class without inject constructor

class Car3 {

In module add a class if not (@Inject constructor of a class)

@Module
internal class MyModule {
@Provides
@Singleton
fun provideCar3(): Car3 = Car3()
}

Add Module in Component and inject your activity

@Singleton
@Component(modules = [MyModule::class])
interface MyComponent {
fun inject(target: MainActivity)
}

In App Class create Component object

class MyApp : Application() {
var myComponent: MyComponent? = null
private set

override fun onCreate() {
super.onCreate()
myComponent = DaggerMyComponent.create()
}
}

In MainActivity

class MainActivity : AppCompatActivity() {
@Inject
lateinit var car3: Car3
@Inject
lateinit var car2: Car2

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

(application as MyApp).myComponent?.inject(this)

Log.i("Dagger_2","${car2.maker()}")
Log.i("Dagger_2","${car3.maker()}")
}
}

if there is error : Dagger classes not created, Build => Rebuild Project

Dagger Hilt

Class with inject constructor

class Car2 @Inject constructor(){

Class without inject constructor

class Car3 {

In module add a class if not (@Inject constructor of a class)

@Module
@InstallIn(SingletonComponent::class)
class MyModule {

@Provides
@Singleton
fun provideCar3(): Car3 = Car3()
}

No need to ‘@Component’

In App Class

@HiltAndroidApp
class MyApp : Application()

In MainActivity

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var car3: Car3
@Inject
lateinit var car2: Car2
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

Log.i("Dagger_Hilt","${car2.maker()}")
Log.i("Dagger_Hilt","${car3.maker()}")
}
}

if there is error : Dagger classes not created, Build => Rebuild Project

Koin

Class (No need to inject constructor)

class Car2 {

Also

class Car3 {

In module

val MyModule = module {

single { Car3() }
single { Car2() }
}

In App Class

class MyApp : Application() {

override fun onCreate() {
super.onCreate()

startKoin {
modules(listOf(MyModule))
}
}
}

In MainActivity

class MainActivity : AppCompatActivity() {
private val car2 : Car2 by inject()
private val car3 : Car3 by inject()

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

Log.i("Koin_","" + car2.maker())
Log.i("Koin_","" + car3.maker())

}
}

Inject : SharedPreferences

Dagger 2

add Class MySharedPreferences

class MySharedPreferences @Inject constructor(private val    mSharedPreferences: SharedPreferences) {
fun putData(key: String?, data: Int) {
mSharedPreferences.edit().putInt(key, data).apply()
}
fun getData(key: String?): Int {
return mSharedPreferences.getInt(key, 0)
}
}

Need Context for create instance of SharedPreferences, so add ContextModule

@Module
class ContextModule(private val context: Context) {
@Provides
fun // @MyApplicationScope
provideContext(): Context {
return context
}

// @MyApplicationScope
@Provides
@Inject
fun provideSharedPreferences(): SharedPreferences {
return context.getSharedPreferences("PrefName", Context.MODE_PRIVATE)
}
}

Add ContextModule to Component

@Singleton
@Component(modules = [MyModule::class, ContextModule::class])
interface MyComponent {
fun inject(target: MainActivity)
}

In App Class : pass the context

class MyApp : Application() {
var myComponent: MyComponent? = null
private set

override fun onCreate() {
super.onCreate()
// myComponent = DaggerMyComponent.create()
myComponent = DaggerMyComponent.builder().contextModule(ContextModule(this)).build()
}
}

In MainActivity

class MainActivity : AppCompatActivity() {
@Inject
lateinit var car3: Car3
@Inject
lateinit var car2: Car2

@Inject
lateinit var mySharedPreferences: MySharedPreferences

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

(application as MyApp).myComponent?.inject(this)

Log.i("Dagger_2","${car2.maker()}")
Log.i("Dagger_2","${car3.maker()}")

mySharedPreferences.putData("mmm", 99)
val value = mySharedPreferences.getData("mmm")
Log.i("ooooooo", "" + value)
}
}

Dagger Hilt

add Class MySharedPreferences

class MySharedPreferences @Inject constructor(private val    mSharedPreferences: SharedPreferences) {
fun putData(key: String?, data: Int) {
mSharedPreferences.edit().putInt(key, data).apply()
}
fun getData(key: String?): Int {
return mSharedPreferences.getInt(key, 0)
}
}

Need Context for create instance of SharedPreferences, but you can use @ApplicationContext directly in Module MyModule

@Module
@InstallIn(SingletonComponent::class)
class MyModule {

@Provides
@Singleton
fun provideCar3(): Car3 = Car3()

@Provides
@Singleton
fun provideSharedPreferences(@ApplicationContext context : Context): SharedPreferences =
context.getSharedPreferences("PrefName", Context.MODE_PRIVATE)
}

In App Class

@HiltAndroidApp
class MyApp : Application()

In MainActivity

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var car3: Car3
@Inject
lateinit var car2: Car2

@Inject
lateinit var mySharedPreferences: MySharedPreferences

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

Log.i("Dagger_Hilt","${car2.maker()}")
Log.i("Dagger_Hilt","${car3.maker()}")

mySharedPreferences.putData("mmm", 99)
val value = mySharedPreferences.getData("mmm")
Log.i("ooooooo", "" + value)
}
}

Koin

add Class MySharedPreferences

class MySharedPreferences constructor(private val  mSharedPreferences: SharedPreferences) {
fun putData(key: String?, data: Int) {
mSharedPreferences.edit().putInt(key, data).apply()
}

fun getData(key: String?): Int {
return mSharedPreferences.getInt(key, 0)
}
}

Need Context for create instance of SharedPreferences, but you can use androidContext() directly in Module MyModule

val MyModule = module {

single { Car3() }
single { Car2() }

single { provideSharedPreferences(androidContext()) }

single{ MySharedPreferences(get()) }
}

private fun provideSharedPreferences(context: Context) : SharedPreferences =
context.getSharedPreferences("PrefName", Context.MODE_PRIVATE)

In App Class : add androidContext(this@MyApp)

class MyApp : Application() {

override fun onCreate() {
super.onCreate()

startKoin {
androidContext(this@MyApp)

modules(listOf(MyModule))
}
}
}

In MainActivity

class MainActivity : AppCompatActivity() {
private val car2 : Car2 by inject()
private val car3 : Car3 by inject()

val mySharedPreferences : MySharedPreferences by inject()

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

Log.i("Koin_","" + car2.maker())
Log.i("Koin_","" + car3.maker())

mySharedPreferences.putData("mmm", 99)
val value = mySharedPreferences.getData("mmm")
Log.i("ooooooo", "" + value)

}
}

Inject : ViewModel

add this in build.grade

// ViewModel and LiveData : lifecycle for ViewModule
def lifecycleVersion = "2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel:2.2.0"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion"

and add this in plugins

// kotlin-android-extensions
id 'kotlin-android-extensions'

A ViewModel holds your app’s UI data in a lifecycle-conscious way that survives configuration changes.
Separating your app’s UI data from your Activity and Fragment classes lets you better follow the single
responsibility principle: Your activities and fragments are responsible for drawing data to the screen,
while your ViewModel can take care of holding and processing all the data needed for the UI.

LiveData is an observable data holder — you can get notified every time the data changes. Unlike Flow, LiveData is lifecycle aware, meaning that it will respect the lifecycle of other components like Activity or Fragment. LiveData automatically stops or resumes observation depending on the lifecycle of the component that listens for changes. This makes LiveData the perfect component to be used for for changeable data that the UI will use or display.

Dagger 2

add class Data

add class MyViewModel

add class ViewModelFactory

Add Module in Component

@Singleton
@Component(modules = [MyModule::class, ContextModule::class, ViewModelModule::class])
interface MyComponent {
fun inject(target: MainActivity)
}

In App Class create Component object

class MyApp : Application() {
var myComponent: MyComponent? = null
private set
override fun onCreate() {
super.onCreate()
myComponent = DaggerMyComponent.create()
}
}

In MainActivity

Dagger Hilt

add class Data

add class MyViewModel

no need class ViewModelFactory

In App Class create Component object

@HiltAndroidApp
class MyApp : Application()

In MainActivity

Koin

add class Data

add class MyViewModel

add MyViewModelModule Module

// inject ViewModel
val MyViewModelModule = module {
single { Data() }

viewModel {
MyViewModel(get())
}
}

In App Class create Component object

class MyApp : Application() {

override fun onCreate() {
super.onCreate()

startKoin {
androidContext(this@MyApp)

modules(listOf(MyModule, MyViewModelModule))
}
}
}

In MainActivity

The source code of application :

continue :

--

--

No responses yet

Write a response