-
-
Notifications
You must be signed in to change notification settings - Fork 727
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parameters in by inject() are not lazy #67
Comments
Hello, Koin is already heavily based on Keep in mind that the dynmaic parameters that you pass, have to be laready evaluated. Here below, a debug log from MVP example with Fragment injecting Presenter (https://github.com/Ekito/koin-samples/tree/master/samples/android-weatherapp):
Presenter is injected for my first use of it. Check if you don't use one of the variable somewhere. |
Hello, class ArcherDetailFragment:BaseFragment()
{
val archerViewModel by
viewModel<ArcherDetailViewModel>(parameters = mapOf(Properties.EXTRA_ARCHER_ID to (getKey<ArcherDetailKey>()?.id?:EmptyUUID)))
} And I need to wait until the onActivityCreated is raised: class ArcherDetailFragment:Fragment()
{
lateinit var archerViewModel:ArcherDetailViewModel
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
archerViewModel = getViewModel(parameters = mapOf(Properties.EXTRA_ARCHER_ID to (getKey<ArcherDetailKey>()?.id?:EmptyUUID)))
}
} The "getKey()" is a method of the baseFragment() fun <T : BaseKey> getKey(): T? = arguments?.getParcelable("KEY") I can live with the second option, but it looks less polished than the first :) Regards |
I have found the issue! The inject function is currently defined like this: inline fun <reified T> ComponentCallbacks.inject(name: String = "", parameters: ParameterMap = emptyMap()) = lazy { (StandAloneContext.koinContext as KoinContext).get<T>(name, parameters) } The problem here is, that we pass the ParameterMap directly to the lazy {} function. This ParameterMap gets created DIRECTLY when the fragment is created. class MyFragment : Fragment() {
val presenter: MyPresenter by inject(parameters = mapOf("activity" to activity!!)
} At this moment the Activity is null, because all properties gets created when a new instance of the fragment is created. The creation of the presenter is lazy like @arnaudgiuliani said, but the ParameterMap does not contain the activity as parameter. A good solution for fixing this issue is to replace the ParameterMap with an paramsFunc() like below: inline fun <reified T> ComponentCallbacks.inject(name: String = "", crossinline paramsFunc:() -> ParameterMap = { emptyMap() }) = lazy { (StandAloneContext.koinContext as KoinContext).get<T>(name, paramsFunc()) } With this implementation the ParameterMap gets created at the same time when the presenter is first needed. At this moment the activity is already created and ready to use. Maybe there are other possible solution to also provide the passed parameters at first creation!? |
Yes, interesting solution @Bodo1981 👍 |
The same with viewModel()... inline fun <reified T : ViewModel> LifecycleOwner.viewModel(
fromActivity: Boolean = true,
key: String? = null,
name: String? = null,
noinline paramsFunc: () -> ParameterMap = { emptyMap() }
): Lazy<T> {
return viewModelByClass(fromActivity, T::class, key, name, paramsFunc)
}
fun <T : ViewModel> LifecycleOwner.viewModelByClass(fromActivity: Boolean = true, clazz: KClass<T>, key: String? = null, name: String? = null, paramsFunc: () -> ParameterMap = { emptyMap() }): Lazy<T> {
return lazy { getViewModelByClass(fromActivity, clazz, key, name, paramsFunc()) }
} |
Ok. Fixed. I migrate all params to be functional. Koin has now a very nice syntax to supply dynamic params (lambda directly opened for parameters): val presenter: MyPresenter by inject { mapOf("key" to myKey) } Just migrate my MVP sample: https://github.com/Ekito/koin-samples/blob/0.9.1/samples/android-weatherapp/app/src/main/kotlin/org/koin/sampleapp/view/search/SearchActivity.kt#L23 You can play with Koin |
After playing around a little bit with the new parameters i came accross another issue.
if you instantiate this fragment the presenter gets created instantly and not on his first call.
this leads to the following exception
currently a workaround is to inject the presenter like this
this works and the presenter gets only created after the first call
i think it would be great if by inject() has the same functionality as by lazy or if you will not change this direct instantiation you could provide another by injectLazy() function or so...
I am looking forward for your feedback
The text was updated successfully, but these errors were encountered: