Koin升级至2.2.2后编译报错:Cannot use 'VM' as reified type parameter. Use a class instead
Hey there, let's work through this Koin upgrade issue you're hitting. I ran into a nearly identical problem when jumping from Koin 2.0.x to 2.2+, so I know exactly what's going on here.
Why This Happens
In Koin 2.0.1, the viewModel() delegate had a handy overload that accepted a KClass<VM> parameter—perfect for your generic base class setup. But starting with Koin 2.2.x, the team shifted the core viewModel() implementation to rely on reified type parameters. The catch? Your VM is a generic type parameter, and the compiler can't "reify" it (meaning it can't lock in the concrete type at compile time), which triggers that error message.
Solution 1: Use getViewModel() with lazy
The quickest fix is to swap out the by viewModel(clazz) delegate with a lazy block that uses Koin's getViewModel() function. This function still supports passing a KClass directly, so it plays nicely with your generic setup:
abstract class ActivityBaseViewModel<out VM : ViewModel>(clazz: KClass<VM>) : AppCompatActivity() { protected val viewModel: VM by lazy { getViewModel(clazz = clazz) } }
This keeps the same lazy initialization behavior as your original code while aligning with Koin's updated API.
Solution 2: Keep the Delegate with a Factory Lambda
If you prefer sticking with the by viewModel() syntax, you can pass a factory lambda to the delegate that fetches the ViewModel using your provided KClass:
abstract class ActivityBaseViewModel<out VM : ViewModel>(clazz: KClass<VM>) : AppCompatActivity() { protected val viewModel: VM by viewModel { get(clazz) } }
This works because the lambda gives you access to Koin's get() function, which still accepts a KClass parameter.
Bonus: Simplify Subclass Usage (Optional)
If you want to eliminate passing KClass to every subclass, you can refactor the base class to let subclasses provide the reified type directly. Here's how that looks:
abstract class ActivityBaseViewModel<VM : ViewModel> : AppCompatActivity() { protected abstract val viewModel: VM } // In your subclass: class HomeActivity : ActivityBaseViewModel<HomeViewModel>() { override val viewModel: HomeViewModel by viewModel() }
This removes the need for passing KClass entirely, though it does require each subclass to explicitly declare its ViewModel type and override the property.
内容的提问来源于stack exchange,提问作者user924

