samedi 30 novembre 2019

Create ViewModel Using Factory with interface as Constructor argument

I am creating a generic class to create the ViewModel with multiple constructor argument. Some of my view model can have no argument or can have 1,2,3 or more arguments

fun <T : ViewModel> LifecycleOwner.injectViewModel(classs: Class<T>, vararg args: Any): T {

    val factory = object : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            val argsType = args.map {it.javaClass}.toTypedArray()
            val constructor = modelClass.getConstructor(*argsType)
            return constructor.newInstance(*args)
        }

    }
    return when (this) {
        is FragmentActivity -> ViewModelProviders.of(this, factory).get(classs)
        is Fragment -> ViewModelProviders.of(this, factory).get(classs)
        else -> throw IllegalStateException("Error Creation ViewModels")
    }
}

This works fine in most of the cases. But in the case when some interface is in parameter of constructor of ViewModel and creating view model by passing class that implements the interface causes following error

Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)  Caused by: java.lang.NoSuchMethodException: [class com.symphony.blogging.author.repository.AuthorRepository]

eg My view model is below

class HomeViewModel(private val repository: AuthorBaseRepository) : ViewModel() {}

Here AuthorBaseRepository is an interface and my activity create ViewModels like this

private val viewModel by lazy {
        val useCase = GetAuthorUseCase(ApiService())
        val cacheSource = AuthorCachedBaseRepository(useCase)
        val remoteSource = AuthorRemoteBaseRepository(useCase)

        injectViewModel(
            HomeViewModel::class.java,
            AuthorRepository(cacheSource, remoteSource, isConnected) as AuthorBaseRepository
        )
    }

If my view model is have concrete class then code work fine like this. here AuthorRepository is concrete class implementing Author Base repository.

class HomeViewModel(private val repository: AuthorRepository) : ViewModel() {}

As soon as I change constructor of My view model to the AuthorBaseRepository(which is the interface) app crashes with above exception.





Aucun commentaire:

Enregistrer un commentaire