Closed silviorp closed 6 years ago
Your code looks good to me. Are you shure you are compiling koin-android-architecture 0.8.2 ??
// Koin for Android Architecture Components
compile "org.koin:koin-android-architecture:0.8.2"
Are you importing correctly?
import org.koin.android.architecture.ext.viewModel
Maybe try declaring the type in the value?
val myViewModel : MyViewModel by viewModel()
The problem was the version I was using, 0.8.0. But now that I was able to import, there's another problem:
Do you guys know how should I proceed? I really like to get the viewModel instance inside my BaseActivity to handle snackbar, toast and other generic observers from my ViewModel.
You don't need the angle brackets for the viewmodel I believe
Scratch that I misunderstood that your activity was generic
What about
val myViewModel : MyViewModel<T> by viewModel()
Hello,
we can't use generic type T
with infered Kotlin parameter :/
Best thing is to add a method to allow such declaration: val myViewModel : MyViewModel<T> by viewModel(T::class)
or something like that.
What I trying to do is receive the type of View Model as parameter and inject a new instance of this type. There's no MyViewModel. The ViewModel types would be received in a generic way. The problem is because it's an inline function with reified type, it's not allowed to receive the type like we have here. It would be amazing to be able to use like this: val myViewModel : T by viewModel(T::class)
or val myViewModel: T by viewModel()
I'm going to try to strip the injection source code and implement a ViewModelFactory to initialize it inside the BaseActivity but this would not benefit from the rest of the library features
After 2 days I had no success trying to make this work. I'm having a hard time working with generics in kotlin, something I could do in Java very easily. I don't want to try another libraries for dependency injection but since I'm in the beginning of a new project in the company I work for, if I can't solve this quickly I'll be forced to try another libs or maybe, write this in Java.
Does
val myViewModel : T by viewModel()
Not work?
Yes Ok. Sorry there was a mistake in my answer. You need to write:
val model: T by viewModel(T::class)
or val model: T by lazy {getViewModel(T::class)}
Let me write a patch 👍
fix is available in current alpha: 0.9.0-alpha-11
API has been updated to have val model: T by viewModel(<KClass<T>>)
and avoid reified types this way.
Your base activity must be like:
class Base Activity<T : ViewModel>(clazz : KClass<T>){
val model : T by viewModel(clazz)
}
We can't pass reified parameters from class.
It worked! Thanks very much!!! I'll try make an extension or something like that to avoid having to pass the class as a parameter but for now, that's working wonderfully!!
Cool :) I close the issue.
@shrpereira Did you manage to avoid having to pass the class as a parameter?
@shrpereira You will be able to get viewModel by class with viewModelByClass()
and getViewModelByClass
. This is the final version of the API fir release 0.9.0
@shrpereira Have you added an extension to not pass class as a parameter to the activity ?
@fathallah92 No. I've used the following approach:
I have a BaseActivity:
open class BaseActivity<out ViewModelType : BaseViewModel>(clazz: KClass<ViewModelType>) :
AppCompatActivity() {
val viewModel: ViewModelType by viewModel(clazz)
}
And on each activity, I pass the viewModel class like this:
class MainActivity : BaseActivity<MainViewModel>(MainViewModel::class) {}
But I'm not coding on this project for some time (it's in production, though), so, probably there are better ways to do it.
@arnaudgiuliani Are there any elegant approach that not pass class as a parameter to the activity?
@arnaudgiuliani Are there any elegant approach that not pass class as a parameter to the activity?
Hope this isn't too late. You can try this:
open class BaseFragment<M : ViewModel> : Fragment() {
val viewModel: M by lazy { getViewModel(viewModelClass()) }
@Suppress("UNCHECKED_CAST")
private fun viewModelClass(): KClass<M> {
// dirty hack to get generic type https://stackoverflow.com/a/1901275/719212
return ((javaClass.genericSuperclass as ParameterizedType)
.actualTypeArguments[0] as Class<M>).kotlin
}
}
@arnaudgiuliani Are there any elegant approach that not pass class as a parameter to the activity?
Hope this isn't too late. You can try this:
open class BaseFragment<M : ViewModel> : Fragment() { val viewModel: M by lazy { getViewModel(viewModelClass()) } @Suppress("UNCHECKED_CAST") private fun viewModelClass(): KClass<M> { // dirty hack to get generic type https://stackoverflow.com/a/1901275/719212 return ((javaClass.genericSuperclass as ParameterizedType) .actualTypeArguments[0] as Class<M>).kotlin } }
There is a problem when using databinding at the same time.
@nEdAy if use ViewDataBinding use need change 0 to 1 because ViewModel is 2 in paramaeters
open class BaseFragment<B : ViewDataBinding, M : ViewModel> : Fragment() {
val viewModel: M by lazy { getViewModel(viewModelClass()) }
@Suppress("UNCHECKED_CAST")
private fun viewModelClass(): KClass<M> {
// dirty hack to get generic type https://stackoverflow.com/a/1901275/719212
return ((javaClass.genericSuperclass as ParameterizedType)
.actualTypeArguments[1] as Class<M>).kotlin
}
}
Is there an example of how this is implemented on a example Fragment? I am getting a No definition found error when I use the above example. The only way I have gotten it to work was going around the lazy and doing a loadKoinModules(module{single{ExampleViewModel()}}) inside the ExampleFragment which kind of defeats the purpose.
@arnaudgiuliani Are there any elegant approach that not pass class as a parameter to the activity?
Hope this isn't too late. You can try this:
open class BaseFragment<M : ViewModel> : Fragment() { val viewModel: M by lazy { getViewModel(viewModelClass()) } @Suppress("UNCHECKED_CAST") private fun viewModelClass(): KClass<M> { // dirty hack to get generic type https://stackoverflow.com/a/1901275/719212 return ((javaClass.genericSuperclass as ParameterizedType) .actualTypeArguments[0] as Class<M>).kotlin } }
I have figured out by myself, quite similar with your approach , thank you for answer, happy coding :D
I did it like this
abstract class BaseFragment<VM: BaseViewModel> : Fragment() {
val viewModel: VM by lazy { getViewModel(clazz) }
abstract var clazz: KClass<VM>
}
I'm trying to follow the documentation using delegate style declaration of ViewModels but I cannot resolve the import in Android Studio.
This is my code:
What I'm doing wrong? Any advice is appreciated.