Android Injection : Simple Example (Dagger 2 — Hilt — Koin) : 1/2
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 :