M Rajoy
M Rajoy

Reputation: 4074

Getting generic class from Kotlin Generic

I have the following class signature:

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

    protected lateinit var viewModel: E

}

Now I want to initialize my viewModel in a generic way using ViewModelProvider, so:

   viewModel = ViewModelProviders.of(this, viewModelFactory)
            .get(MyViewModel::class)

Given that MyViewModel class will be provided in the generic type, I'd say this could potentially be abstracted into the BaseActivity so I dont have to do it for every Activity that extends it.

I tried with:

inline fun <reified E : ViewModel> getViewModelClass() = E::class.java

But then when doing:

viewModel = ViewModelProviders.of(this, viewModelFactory)
            .get(getViewModelClass())

I get Cannot use E as reified type paramter. Use class instead

Is there a solution to this?

Upvotes: 0

Views: 1485

Answers (3)

Yekta Sarıoğlu
Yekta Sarıoğlu

Reputation: 1555

https://stackoverflow.com/a/52107111/8832537

You should check this guy's solution. The only downside of his approach is he uses Reflection API to get the generic parameter. I researched a lot but didn't find a solution that doesn't use reflection. If you did find it, let me know. That would be more convenient.

Upvotes: 1

Alexey Romanov
Alexey Romanov

Reputation: 170713

E in BaseActivity can't be reified, so you can't pass it to any methods which take a reified E.

Your best option may just be to accept the class as a constructor parameter.

abstract class BaseActivity<E : ViewModel>(private val modelClass: Class<E>) : AppCompatActivity() {

    protected lateinit var viewModel: E

    ... viewModel = ViewModelProviders.of(this, viewModelFactory)
        .get(modelClass)
}

If BaseActivity wasn't abstract, you could add a factory method:

// outside BaseActivity class itself
fun <reified E : BaseModel> BaseActivity() = BaseActivity(E::class.java)

but it wouldn't help when extending it.

Upvotes: 3

Keshav Aggarwal
Keshav Aggarwal

Reputation: 763

You ca do it in this way:

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

protected lateinit var viewModel: E

abstract fun getViewModel():E

override fun onCreate(savedInstanceState: Bundle?){
    super.onCreate(savedInstanceState)
    viewModel = ViewModelProviders.of(this, viewModelFactory)
        .get(getViewModel())
}

}

Now, you can extend any class from BaseActivity and override the getViewModel() function returning the respective ViewModel class.

Hope this helps.

EDIT

Try this once:

 inline fun <reified E> getViewModelClass(): Class<E> {
    return E::class.java
}

and use it like this:

viewModel = ViewModelProviders.of(this, viewModelFactory)
        .get(getViewModelClass())

Upvotes: 1

Related Questions