9

I am trying to write a generic base activity, that specifies it's ViewModel type a generic parameter:

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

Now I am trying to write a lazy initialized property for my ViewModel:

val viewModel by lazy { ViewModelProviders.of(this, getFactory()).get(T) }

The error that is displayed is Type Parameter T is not an expression

Also using ::class or ::class.java did not help. Can anyone explain the problem?

EDIT: I tried to use a reified inline function like this:

inline fun <reified T : ViewModel?> AppCompatActivity.obtainViewModel(factory: ViewModelProvider.Factory): T {
    return ViewModelProviders.of(this, factory).get(T::class.java)
}

And used it like this:

abstract class BaseActivity<T> : AppCompatActivity() {
    val viewModel by lazy { obtainViewModel<T>(getFactory()) 
}

Now I get the error, that T cannot be used as a reified parameter.

EDIT2: The best solution so far seems to be this: Link, but its overhead to implement the abstract token in every extending class.

2

2 Answers 2

2

Your class has a type parameter T, which unfortunately gets erased at runtime. As a result, the call get(T) does not work (I guess the method expects a Class actually?).

You seem to have already noticed that and thus tried to fix it with encapsulating the handling into a method using reified type. Yet, you cannot pass T as a reified parameter since this type will already be erased when the reified-typed method is called. As a result, obtainViewModel<T> will not work either. What you can do, is using T for ordinary generic methods, which the following demonstrates:

class Typed<T> {
    val lazyProp by lazy {
        listOf<T>()
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

So there is no way to achieve the behaviour I was trying to implement?
Not that way I'm afraid. What do you think about the suggestion I just added
Thank you for your answer :) Unfortunately, this would make the code I am trying to wrap away become more complicated than it was before. :/
have you found another way to do this?
@ArchieG.Quiñones not sure if u have found the solution, but check out my suggestion here stackoverflow.com/a/53480529/5315499
|
2

maybe a bit late, but I guess this could be the elegant way to achieve it:

abstract class BaseActivity<T : ViewModel>(
    private var modelClass: Class<T>) : AppCompatActivity() {

    val viewModel by lazy { 
        ViewModelProviders.of(this, getFactory()).get(modelClass) 
    }

}

and then

class SampleActivity : BaseActivity<SampleViewModel>(SampleViewModel::class.java) {
    // use viewModel from here
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.