Erik
02/26/2020, 1:31 PMstartKoin {}
. So basically I want to have a lib-private KoinApplication
/ Koin
instance. How do I approach this? It used to work on v2.0.1.Erik
02/26/2020, 1:31 PMstartKoin {}
(in onCreate), I get an exception:
java.lang.IllegalStateException: No Koin Context configured. Please use startKoin or koinApplication DSL.
Erik
02/26/2020, 1:32 PMkoinApplication
DSL in my libErik
02/26/2020, 1:33 PMstartKoin {}
(in onCreate), I get an exception too:
E java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
E at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:502)
E at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
E Caused by: java.lang.reflect.InvocationTargetException
E at java.lang.reflect.Method.invoke(Native Method)
E at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
E ... 1 more
E Caused by: org.koin.core.error.NoBeanDefFoundException: No definition found for class:'com.example.MyViewModel'. Check your definitions!
Erik
02/26/2020, 1:34 PMby sharedViewModel()
and my conclusion is that somehow Koin looks in the application's Koin instance for the view model definition, which logically is not there. It should have used the lib's koin instance.Erik
02/26/2020, 1:36 PMKoinComponent
interface that provide's the lib's Koin
instance, yet, somehow this no longer works.Erik
02/26/2020, 1:40 PMErik
02/26/2020, 1:41 PMrequireActivity()
suddenly changes the LifecycleOwner
that this call runs onErik
02/26/2020, 1:41 PMErik
02/26/2020, 1:42 PMKoin
instance that my fragment uses to obtain the shared view modelErik
02/26/2020, 1:49 PMby sharedViewModel()
the fragment's activity's must either be a KoinComponent
(which isn't the case for me) or there must be a global Koin instance registered with KoinContextHandler
(which also isn't necessarily the case, nor is that the instance where the view model is defined!).Erik
02/26/2020, 1:49 PMKoinComponent
. This makes Koin leak from my library into its app clients....Erik
02/26/2020, 1:50 PMarnaud.giuliani
02/26/2020, 2:04 PMKoinContextHandler
is the new component that let us setup the GlobalContext
arnaud.giuliani
02/26/2020, 2:05 PMarnaud.giuliani
02/26/2020, 2:05 PMarnaud.giuliani
02/26/2020, 2:05 PMarnaud.giuliani
02/26/2020, 2:06 PMKoinContextHandler.getOrNull()
can tell you if you have already a Koin instancearnaud.giuliani
02/26/2020, 2:07 PMErik
02/26/2020, 2:23 PMErik
02/26/2020, 2:24 PMKoinContextHandler.getOrNull()
in my library, because in any case I don't want to know about or touch the app's Koin instancearnaud.giuliani
02/26/2020, 2:24 PMloadKoinModules
or isolated koinApplication
instance?Erik
02/26/2020, 2:25 PMFragment.sharedViewModels()
that the activity uses the same koin instance. This is an incorrect assumptionErik
02/26/2020, 2:25 PMkoinApplication
instancearnaud.giuliani
02/26/2020, 2:25 PMarnaud.giuliani
02/26/2020, 2:26 PMKoinComponent
interfaceErik
02/26/2020, 2:26 PMErik
02/26/2020, 2:27 PMErik
02/26/2020, 2:27 PMKoinComponent
leaks into the public API of my libarnaud.giuliani
02/26/2020, 2:27 PMarnaud.giuliani
02/26/2020, 2:28 PMarnaud.giuliani
02/26/2020, 2:30 PMErik
02/26/2020, 2:30 PMErik
02/26/2020, 2:31 PMandroidx.lifecycle:lifecycle-common-java8:2.2.0
, probably transitively includes viewmodel:2.2.0
Erik
02/26/2020, 2:31 PMarnaud.giuliani
02/26/2020, 2:32 PMarnaud.giuliani
02/26/2020, 2:32 PMErik
02/26/2020, 2:33 PMandroidx.lifecycle:lifecycle-viewmodel:2.2.0
transitivelyarnaud.giuliani
02/26/2020, 2:33 PMErik
02/26/2020, 2:36 PMrequireActivity()
call:
https://github.com/InsertKoinIO/koin/blob/38c855c1f22f4f1d3afe8555ff7ef2e8dd87ad99/koin-projects/koin-androidx-viewmodel/src/main/java/org/koin/androidx/viewmodel/ext/android/FragmentExt.kt#L55
The impact was that getKoin()
would be called on my fragment, which is internal in my lib.
In Koin v2.1.0 getKoin()
is called on the activity, which is public in my lib and therefore should not be my custom KoinComponent
implementation.Erik
02/26/2020, 2:38 PMFragment.sharedViewModel()
from my fragment that is a custom KoinComponent
, that under water a Koin
instance is obtained from the activity instead!Erik
02/26/2020, 2:38 PMErik
02/26/2020, 2:40 PMclass MyActivity : Activity() {
// Hosts MyFragmentOne and MyFragmentTwo
}
internal class MyFragmentOne: Fragment(), MyKoinComponent {
val vm: MyViewModel by sharedViewModel()
}
internal class MyFragmentTwo : Fragment(), MyKoinComponent {
val vm: MyViewModel by sharedViewModel()
}
Erik
02/26/2020, 2:43 PMFragment.sharedViewModel()
call would happen using the MyKoinComponent
, but it does not. Koin assumes that the activity also is a MyKoinComponent
or that the default global Koin application is the correct instance. Both assumptions are wrong.Erik
02/26/2020, 2:45 PMrequireActivity()
used in the first place in Fragment.sharedViewModel()
? Why can't the Koin
instance be obtained from the fragment itself? Suggestion: try to obtain a koin instance from the fragment, then from the activity, then try the global instancearnaud.giuliani
02/26/2020, 3:11 PMarnaud.giuliani
02/26/2020, 3:11 PMarnaud.giuliani
02/26/2020, 3:21 PMErik
02/26/2020, 3:21 PMErik
02/26/2020, 3:21 PMErik
02/26/2020, 3:21 PMErik
02/26/2020, 3:22 PMErik
02/26/2020, 3:22 PMarnaud.giuliani
02/26/2020, 3:22 PMarnaud.giuliani
02/26/2020, 3:22 PMI hope it doesn’t break other use casesthat’s why I need people to help me test in beta also 🙂
arnaud.giuliani
02/26/2020, 4:59 PM2.1.1-alpha-1
Erik
02/26/2020, 8:08 PM2.1.0
and that version is
diff --git a/org/koin/androidx/viewmodel/ext/android/FragmentExt.kt b/org/koin/androidx/viewmodel/ext/android/FragmentExt.kt
index 9db6749..475f198 100644
--- a/org/koin/androidx/viewmodel/ext/android/FragmentExt.kt
+++ b/org/koin/androidx/viewmodel/ext/android/FragmentExt.kt
@@ -16,7 +16,10 @@
package org.koin.androidx.viewmodel.ext.android
import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModel
+import org.koin.android.ext.android.getKoin
+import org.koin.androidx.viewmodel.koin.getViewModel
import org.koin.core.parameter.ParametersDefinition
import org.koin.core.qualifier.Qualifier
import kotlin.reflect.KClass
@@ -52,7 +55,8 @@ fun <T : ViewModel> Fragment.getSharedViewModel(
qualifier: Qualifier? = null,
parameters: ParametersDefinition? = null
): T {
- return requireActivity().getViewModel(
+ return getKoin().getViewModel(
+ this.activity as FragmentActivity,
clazz,
qualifier,
parameters
Why do you get the activity as FragmentActivity
? Why not requireActivity()
here? That returns a FragmentActivity
, not a FragmentActivity?
.Erik
02/26/2020, 8:19 PMby sharedViewModel()
call now uses the fragment to call ComponentCallbacks.getKoin()
Erik
02/26/2020, 8:24 PMKoinComponent
, but the attached activity is. A user of by sharedViewModel()
might assume that? If you think that's a valid use case, you could add a branch to the when
expression in `ComponentCallbacks.getKoin()`:
/**
* Get Koin context
*/
fun ComponentCallbacks.getKoin() = when (this) {
is KoinComponent -> this.getKoin()
is Fragment -> requireActivity().getKoin()
else -> KoinContextHandler.get()
}
arnaud.giuliani
02/27/2020, 9:04 AMarnaud.giuliani
02/27/2020, 9:04 AMErik
02/27/2020, 9:10 AMgetKoin().getViewModel(
this.activity as FragmentActivity,
clazz,
qualifier,
parameters
)
where this.activity as FragmentActivity
is used as a LifecycleOwner
. Why not use this
, i.e. the Fragment
itself, as the lifecycle owner?arnaud.giuliani
02/27/2020, 9:11 AMarnaud.giuliani
02/27/2020, 9:11 AMErik
02/27/2020, 9:11 AMErik
02/27/2020, 9:11 AMrequireActivty()
instead?arnaud.giuliani
02/27/2020, 9:12 AMarnaud.giuliani
02/27/2020, 9:13 AMrequireActivty()
will return a FragmentActivity?Erik
02/27/2020, 9:13 AMfun <T : ViewModel> Scope.getViewModel(
viewModelStoreOwner: ViewModelStoreOwner,
clazz: KClass<T>,
qualifier: Qualifier? = null,
parameters: ParametersDefinition? = null
): T
Erik
02/27/2020, 9:14 AMfragment:1.2.0
yes:
@NonNull
public final FragmentActivity requireActivity() { ... }
arnaud.giuliani
02/27/2020, 9:15 AMErik
02/27/2020, 9:21 AMarnaud.giuliani
02/27/2020, 9:37 AMrequireActivy
works without any extra depsarnaud.giuliani
02/27/2020, 9:51 AMarnaud.giuliani
02/27/2020, 9:51 AMErik
02/27/2020, 10:42 AMErik
02/27/2020, 11:06 AMarnaud.giuliani
02/27/2020, 1:17 PM