Skip to content

Instantly share code, notes, and snippets.

@adamarthurryan
Forked from tinmegali/App.kt
Created August 9, 2017 19:18
Show Gist options
  • Save adamarthurryan/6a58e255f10efbfc688988d6ec6b4d95 to your computer and use it in GitHub Desktop.
Save adamarthurryan/6a58e255f10efbfc688988d6ec6b4d95 to your computer and use it in GitHub Desktop.
Injecting ViewModel with Dagger2 on Android using Kotlin
class App : Application(), HasActivityInjector {
@Inject lateinit var activityInjector: DispatchingAndroidInjector<Activity>
override fun activityInjector(): AndroidInjector<Activity> {
return activityInjector
}
override fun onCreate() {
super.onCreate()
DaggerAppComponent.builder()
.build()
.inject(this)
}
}
package com.tinmegali.daggerwithkotlin.dagger
import com.tinmegali.daggerwithkotlin.App
import com.tinmegali.daggerwithkotlin.dagger.activities.ActivitiesModule
import com.tinmegali.daggerwithkotlin.dagger.fragments.FragmentsModule
import com.tinmegali.daggerwithkotlin.dagger.viewModels.ViewModelModule
import dagger.Component
import dagger.android.AndroidInjectionModule
import javax.inject.Singleton
@Singleton
@Component(modules = arrayOf(
AndroidInjectionModule::class,
ViewModelModule::class
))
interface AppComponent {
fun inject(app: App)
}
class MainActivity : LifecycleActivity() {
//...
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
var mainViewModel: MainActivityModel? = null
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this) // Dagger
super.onCreate(savedInstanceState)
//..
mainViewModel = ViewModelProviders.of(this, viewModelFactory)
.get(MainActivityModel::class.java)
}
}
class MainActivityModel
@Inject constructor(
private var noteDAO: NoteDAO,
private var userDAO: UserDAO
): ViewModel(), AnkoLogger {
private var notesData: LiveData<List<Note>>? = null
fun getNotes( ): LiveData<List<Note>>? {
return notesData
}
fun subscribeToNotesDBChanges( callback: OnSync ) {
doAsync {
notesData = noteDAO.findAllNotedObservable()
info("Notes received.")
callback.notesReceived()
}
}
public interface OnSync {
fun notesReceived( )
}
}
package com.tinmegali.daggerwithkotlin.dagger.viewModels
import com.tinmegali.daggerwithkotlin.MainActivityModel
import dagger.Component
@Component( modules = arrayOf(
ViewModelModule::class
))
interface ViewModelComponent {
// inject your view models
fun inject( mainViewModel: MainActivityModel )
}
package com.tinmegali.oauth2restclient.dagger
import android.arch.lifecycle.ViewModel
import android.arch.lifecycle.ViewModelProvider
import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Singleton
@Suppress("UNCHECKED_CAST")
@Singleton
class ViewModelFactory @Inject
constructor(
private val creators: Map<Class<out ViewModel>,
@JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
var creator: Provider<out ViewModel>? = creators[modelClass]
if (creator == null) {
for ((key, value) in creators) {
if (modelClass.isAssignableFrom(key)) {
creator = value
break
}
}
}
if (creator == null) {
throw IllegalArgumentException("unknown model class " + modelClass)
}
try {
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
package com.tinmegali.daggerwithkotlin.dagger.viewModels
import android.arch.lifecycle.ViewModel
import java.lang.annotation.Documented
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import dagger.MapKey
import kotlin.reflect.KClass
@MustBeDocumented
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(RetentionPolicy.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
package com.tinmegali.daggerwithkotlin.dagger.viewModels
import android.arch.lifecycle.ViewModel
import android.arch.lifecycle.ViewModelProvider
import com.tinmegali.daggerwithkotlin.MainActivityModel
import com.tinmegali.oauth2restclient.dagger.ViewModelFactory
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
@Module
abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey( MainActivityModel::class )
// Bind your View Model here
abstract fun bindMainViewModel( mainViewModel: MainActivityModel ): ViewModel
@Binds
abstract fun bindViewModelFactory( factory: ViewModelFactory):
ViewModelProvider.Factory
}
@springeye
Copy link

If you use @provides instead of @Inject, ViewModel will be wrong。

class MainActivityModel
constructor(
val otherParams:String,
            private var noteDAO: NoteDAO,
            private var userDAO: UserDAO
    ): ViewModel(), AnkoLogger {

    private var notesData: LiveData<List<Note>>? = null

    fun getNotes( ): LiveData<List<Note>>? {
        return notesData
    }

    fun subscribeToNotesDBChanges( callback: OnSync ) {
        doAsync {
            notesData = noteDAO.findAllNotedObservable()
            info("Notes received.")
            callback.notesReceived()

        }
    }

    public interface OnSync {
        fun notesReceived( )
    }

}
    @IntoMap
    @ViewModelKey(MainActivityModel::class)
    @Provides
    ViewModel provideMainViewModel(noteDao:NoteDAO,userDao:UserDao) {
        val otherParams="test"
        return  MainActivityModel(otherParams,noteDao:NoteDAO, userDao:UserDao);
    }

@ValCanBuild
Copy link

Where is ViewModelComponent used?

@ayooladedeji
Copy link

@ValCanBuild did you figure it out?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment