silvio.pereira
silvio.pereira

Reputation: 538

How to initialize/inject generic ViewModel in BaseActivity by Koin injection on Android/Kotlin App

I'm building the architecture of a new Android application using Kotlin and Android Architecture Components (ViewModel, LiveData) and I'm also using Koin as my dependency injection provider.

The problem is that I'm not been able to initialize the ViewModel in a generic way inside my BaseActivity via koin injection. The current code looks like this:

abstract class BaseActivity<ViewModelType : ViewModel> : AppCompatActivity() {

    // This does not compile because of the generic type
    private val viewModel by lazy {
        // Koin implementation to inject ViewModel
        getViewModel<ViewModelType>()
    }

    @CallSuper
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Fabric.with(this, Crashlytics())
    }

    /**
     * Method needed for Calligraphy library configuration
     */
    @CallSuper
    override fun attachBaseContext(newBase: Context) {
        super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase))
    }
}

I'd like to know if is there a way to do this in Kotlin because I'm pretty sure I would be able to do in Java easily. Thanks.

Upvotes: 4

Views: 6267

Answers (3)

Akbolat SSS
Akbolat SSS

Reputation: 2071

Here is example of not passing Class and Generic to base implementation

In your base fragment/activity:

abstract class BaseFragment<T : BaseViewModel> : Fragment() {

  ...

  @Suppress("UNCHECKED_CAST")
  private val clazz: KClass<T> = ((this.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>).kotlin

  protected val viewModel: T by viewModel(clazz = clazz)
  
  ...
}

It looks ugly, but it works.

Upvotes: 0

Arnaud Giuliani
Arnaud Giuliani

Reputation: 15

you can use a delegate version declaration for your ViewModel and avoid using directly a lazy expression. Try with this:

abstract class BaseActivity<T : ViewModel> : AppCompatActivity() {

    val model by viewModel<T>()

}

This will give you a lazy of

getViewModel<T>()

Throw an eye on the quick ref: https://insert-koin.io/docs/1.0/getting-started/android-viewmodel/

Hope it will help.

Upvotes: -3

silvio.pereira
silvio.pereira

Reputation: 538

The solution was provided by the koin team in version 0.9.0-alpha-11 and the final code looks like this:

open class BaseActivity<out ViewModelType : BaseViewModel>(clazz: KClass<ViewModelType>) :
    AppCompatActivity() {

    val viewModel: ViewModelType by viewModel(clazz)

    fun snackbar(message: String?) {
        message?.let { longSnackbar(find(android.R.id.content), it) }
    }

    fun toast(message: String?) {
        message?.let { longToast(message) }
    }
}

Upvotes: 7

Related Questions