如何使用 Koin 在 BaseFragment 中注入 viewModel
How to inject viewModel in BaseFragment using Koin
我已经创建了一个抽象 BaseFragment
class 它将被其他具体 Fragment
class 扩展。我想使用 Koin
在我的 BaseFragment
中注入 ViewModel
。这是我的 BaseFragment:
abstract class BaseFragment<out VM : BaseViewModel, DB : ViewDataBinding>(private val mViewModelClass: Class<VM>) : Fragment() {
val viewModel: VM by viewModel()
open lateinit var binding: DB
fun init(inflater: LayoutInflater, container: ViewGroup) {
binding = DataBindingUtil.inflate(inflater, getLayoutRes(), container, false)
}
open fun init() {}
@LayoutRes
abstract fun getLayoutRes(): Int
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
init(inflater, container!!)
init()
super.onCreateView(inflater, container, savedInstanceState)
return binding.root
}
open fun refresh() {}
}
但是我做不到。我正在使用 2.0.1
版本的 Koin。
我也有同样的情况。您也可以这样做:
在扩展 BaseFragment 时将 ViewModel 添加为抽象并设置值。
我的 BaseFragment 有:
abstract class BaseFragment<Binding : ViewDataBinding, ViewModel : BaseViewModel> : Fragment() {
protected abstract val mViewModel: ViewModel
protected lateinit var bindingObject: Binding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
bindingObject = DataBindingUtil.inflate(inflater, getLayoutResId(), container, false)
return bindingObject.root
}
/**
* Get layout resource id which inflate in onCreateView.
*/
@LayoutRes
abstract fun getLayoutResId(): Int
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
doDataBinding()
}
/**
* Do your other stuff in init after binding layout.
*/
abstract fun init()
private fun doDataBinding() {
bindingObject.lifecycleOwner = viewLifecycleOwner // it is extra if you want to set life cycle owner in binding
// Here your viewModel and binding variable imlementation
bindingObject.setVariable(BR.viewModel, mViewModel) // In all layout the variable name should be "viewModel"
bindingObject.executePendingBindings()
init()
}
}
这是我实际的 Fragment 实现:
class FragmentComments : BaseFragment<FragmentCommentsBinding, FragmentCommentsVM>() {
// Here is the your viewmodel imlementation
override val mViewModel: FragmentCommentsVM by viewModel()
override fun getLayoutResId(): Int = [fragment layout id like "R.layout.fragment_com"]
override fun init() {
...
}
希望对您有所帮助。如果需要更多帮助,请告诉我!
我目前正在解决同样的问题,查看Koin的源代码,by viewModel()
提供kotlin Lazy
/**
* Lazy get a viewModel instance
*
* @param qualifier - Koin BeanDefinition qualifier (if have several ViewModel beanDefinition of the same type)
* @param parameters - parameters to pass to the BeanDefinition
* @param clazz
*/
fun <T : ViewModel> LifecycleOwner.viewModel(
clazz: KClass<T>,
qualifier: Qualifier? = null,
parameters: ParametersDefinition? = null
): Lazy<T> = lazy { getViewModel(clazz, qualifier, parameters) }
它在初始化时调用另一个 LifecycleOwner 扩展方法,该方法执行 viewModel 实例的实际解析:
/**
* Lazy getByClass a viewModel instance
*
* @param clazz - Class of the BeanDefinition to retrieve
* @param qualifier - Koin BeanDefinition qualifier (if have several ViewModel beanDefinition of the same type)
* @param parameters - parameters to pass to the BeanDefinition
*/
fun <T : ViewModel> LifecycleOwner.getViewModel(
clazz: KClass<T>,
qualifier: Qualifier? = null,
parameters: ParametersDefinition? = null
): T {
return getKoin().getViewModel(
ViewModelParameters(
clazz,
this@getViewModel,
qualifier,
parameters = parameters
)
)
}
我还没有尝试过,但可以肯定地说,如果我直接在我的 BaseFragment 中调用此方法,它应该以相同的方式工作,我的 BaseFragment 看起来像:
abstract class BaseFragment<VM : ViewModel> : Fragment() {
lateinit var viewModel: VM
abstract val viewModelClass: KClass<VM>
override fun onCreate(savedInstanceState: Bundle?) {
viewModel = getViewModel(clazz = viewModelClass)
super.onCreate(savedInstanceState)
}
}
我已经创建了一个抽象 BaseFragment
class 它将被其他具体 Fragment
class 扩展。我想使用 Koin
在我的 BaseFragment
中注入 ViewModel
。这是我的 BaseFragment:
abstract class BaseFragment<out VM : BaseViewModel, DB : ViewDataBinding>(private val mViewModelClass: Class<VM>) : Fragment() {
val viewModel: VM by viewModel()
open lateinit var binding: DB
fun init(inflater: LayoutInflater, container: ViewGroup) {
binding = DataBindingUtil.inflate(inflater, getLayoutRes(), container, false)
}
open fun init() {}
@LayoutRes
abstract fun getLayoutRes(): Int
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
init(inflater, container!!)
init()
super.onCreateView(inflater, container, savedInstanceState)
return binding.root
}
open fun refresh() {}
}
但是我做不到。我正在使用 2.0.1
版本的 Koin。
我也有同样的情况。您也可以这样做:
在扩展 BaseFragment 时将 ViewModel 添加为抽象并设置值。
我的 BaseFragment 有:
abstract class BaseFragment<Binding : ViewDataBinding, ViewModel : BaseViewModel> : Fragment() {
protected abstract val mViewModel: ViewModel
protected lateinit var bindingObject: Binding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
bindingObject = DataBindingUtil.inflate(inflater, getLayoutResId(), container, false)
return bindingObject.root
}
/**
* Get layout resource id which inflate in onCreateView.
*/
@LayoutRes
abstract fun getLayoutResId(): Int
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
doDataBinding()
}
/**
* Do your other stuff in init after binding layout.
*/
abstract fun init()
private fun doDataBinding() {
bindingObject.lifecycleOwner = viewLifecycleOwner // it is extra if you want to set life cycle owner in binding
// Here your viewModel and binding variable imlementation
bindingObject.setVariable(BR.viewModel, mViewModel) // In all layout the variable name should be "viewModel"
bindingObject.executePendingBindings()
init()
}
}
这是我实际的 Fragment 实现:
class FragmentComments : BaseFragment<FragmentCommentsBinding, FragmentCommentsVM>() {
// Here is the your viewmodel imlementation
override val mViewModel: FragmentCommentsVM by viewModel()
override fun getLayoutResId(): Int = [fragment layout id like "R.layout.fragment_com"]
override fun init() {
...
}
希望对您有所帮助。如果需要更多帮助,请告诉我!
我目前正在解决同样的问题,查看Koin的源代码,by viewModel()
提供kotlin Lazy
/**
* Lazy get a viewModel instance
*
* @param qualifier - Koin BeanDefinition qualifier (if have several ViewModel beanDefinition of the same type)
* @param parameters - parameters to pass to the BeanDefinition
* @param clazz
*/
fun <T : ViewModel> LifecycleOwner.viewModel(
clazz: KClass<T>,
qualifier: Qualifier? = null,
parameters: ParametersDefinition? = null
): Lazy<T> = lazy { getViewModel(clazz, qualifier, parameters) }
它在初始化时调用另一个 LifecycleOwner 扩展方法,该方法执行 viewModel 实例的实际解析:
/**
* Lazy getByClass a viewModel instance
*
* @param clazz - Class of the BeanDefinition to retrieve
* @param qualifier - Koin BeanDefinition qualifier (if have several ViewModel beanDefinition of the same type)
* @param parameters - parameters to pass to the BeanDefinition
*/
fun <T : ViewModel> LifecycleOwner.getViewModel(
clazz: KClass<T>,
qualifier: Qualifier? = null,
parameters: ParametersDefinition? = null
): T {
return getKoin().getViewModel(
ViewModelParameters(
clazz,
this@getViewModel,
qualifier,
parameters = parameters
)
)
}
我还没有尝试过,但可以肯定地说,如果我直接在我的 BaseFragment 中调用此方法,它应该以相同的方式工作,我的 BaseFragment 看起来像:
abstract class BaseFragment<VM : ViewModel> : Fragment() {
lateinit var viewModel: VM
abstract val viewModelClass: KClass<VM>
override fun onCreate(savedInstanceState: Bundle?) {
viewModel = getViewModel(clazz = viewModelClass)
super.onCreate(savedInstanceState)
}
}