Merthan Erdem
02/02/2020, 4:39 PMclass HomeFragment : ViewModelFragment<HomeViewModel>(R.layout.fragment_home,HomeViewModel::class)
The method Koin uses to get the ViewModel looks like this:
fun <T : ViewModel> SavedStateRegistryOwner.getViewModel(
clazz: KClass<T>,
qualifier: Qualifier? = null,
parameters: ParametersDefinition? = null
): T {
return getKoin().getViewModel(this, clazz, qualifier, parameters)
}
And at last, my Base class looks like this:
// Created by Merthan Erdem
// We need to pass the generic class because only
// then will the subclass have access to the specific viewmodel methods that it
// We need to pass the actual class (right) because Koin can't use generic classes
abstract class ViewModelFragment<VM : ViewModel>(@LayoutRes val layout: Int, private val viewModelClass: KClass<VM>) : Fragment() {
// Accessible, but generic, won't have specific methods/fields, see getSpecificBinding()
open var binding: ViewDataBinding? = null
open lateinit var viewModel: VM
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Get binding (of passed type) for the passed layout, results in null when binding not available
binding = DataBindingUtil.inflate(inflater, layout, container, false)
// Set lifecycleowner to the current class
binding?.lifecycleOwner = this
// Get ViewModel of passed type from Koin (needs an actual class object/reified, not a generic)
viewModel = getViewModel(viewModelClass)
// If this class had a Binding, return it's root otherwise use inflater to retrieve view
return binding?.root ?: inflater.inflate(layout, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding?.setVariable(BR.viewModel, viewModel)
}
// Returns a binding of the specific type (instead of ViewDataBinding),
// which allows access to non-generic methods and fields
inline fun <reified specific : ViewDataBinding> getSpecificBinding() = binding as? specific
}
Any idea how I could remove the class parameter?
I am pretty sure that the Generic parameter is required because otherwise (e.g. when saying)
open lateinit var viewModel: ViewModel
instead of
open lateinit var viewModel: VM
The inheriting class doesn't get access to methods and fields that It's viewmodel has, only to stuff that the ViewModel class has in general
Additionally, is there a better way to get the specific binding than to use the method that I created? I know it's possible to accept the Binding as a Generic parameter as well but that also seems unnecessary.
Thanks for your help.