Reputation: 538
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
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
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
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