1

我正在尝试从 2.1.6 -> 3.0.2 升级我的 koin 使用,并且在使用范围注入时遇到问题。

我有 MVP,其中 Activity/Fragment 是视图,我想在演示者中注入视图。

所以我有

module {
    scope(named<MainActivity>()) {
    scoped<View> { getSource() }
    scoped<Presenter> {
         MainPresenter(
             view = get()
         )
    }
}

在 2.1.6 中,我曾经这样做过,一切都很好:

class MainActivity :
    AppCompatActivity(),
    MainContract.View {

    private val presenter: MainContract.Presenter by currentScope.inject()
    ...
}

然后在 MainActivity 我现在有:

class MainActivity :
    AppCompatActivity(),
    MainContract.View,
    AndroidScopeComponent {
    override val scope : Scope by activityScope()
    private val presenter: MainContract.Presenter by scope.inject()

...
}

和主持人:

   class MainPresenter(
       private val view: MainContract.View
   ){
       ...
   }

但它无法获取源对象,我得到错误:

Instance creation error : could not create instance for [Single:'uk.co.sentinelweb.cuer.app.ui.main.MainContract$View',scope:q:'uk.co.sentinelweb.cuer.app.ui.main.MainActivity']: java.lang.IllegalStateException: Can't use Scope source for uk.co.sentinelweb.cuer.app.ui.main.MainContract$View - source is:null

(即,当它尝试创建演示者时,它找不到范围内的 MainActivity)

这是现有代码(使用 2.1.6) https://github.com/sentinelweb/cuer/blob/develop/app/src/main/java/uk/co/sentinelweb/cuer/app/ui/main/MainActivity .kt

我在这里有更多的重写工作吗?我正在努力在 koin 文档中找到一个范围注入的好例子,而且很多看起来都很旧。很多项目似乎没有使用范围。

因此,如果有人能告诉我这里出了什么问题,或者给我指出一个类似 id 的像样的例子,非常感谢!

4

1 回答 1

0

So it seems for the lifecycle aware extension methods it just doesnt set the scope variable - perhaps they are paranoid about mempory leaks but since the scope is cleared and on the destroy lifecycle method - this shouldnt be a problem really.

My solution was to just make new extension methods which actually just pass in the source - I am not sure why this would be a problem. There is an issue here for it https://github.com/InsertKoinIO/koin/issues/851

package xxx

import android.app.Service
import androidx.activity.ComponentActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.LifecycleOwner
import org.koin.android.scope.AndroidScopeComponent
import org.koin.android.scope.createScope
import org.koin.android.scope.getScopeOrNull
import org.koin.androidx.scope.LifecycleScopeDelegate
import org.koin.core.Koin
import org.koin.core.component.getScopeId
import org.koin.core.component.getScopeName
import org.koin.core.context.GlobalContext
import org.koin.core.context.KoinContext
import org.koin.core.scope.Scope
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/** copied from org.koin.androidx.scope.FragmentExt but scope wont link as fragment is not attached */
fun ComponentActivity.activityScopeWithSource() = LifecycleScopeWithSourceDelegate(this)

/** copied from org.koin.androidx.scope.FragmentExt but scope wont link as fragment is not attached */
fun Fragment.fragmentScopeWithSource() = LifecycleScopeDelegate(this) { koin: Koin ->
    koin.createScope(getScopeId(), getScopeName(), this)
}

/** links the fragment scope to the activity scope */
fun Fragment.linkScopeToActivity() {
    (this as AndroidScopeComponent).scope.linkTo((requireActivity() as AndroidScopeComponent).scope)
}

/** copied from org.koin.android.scope.ServiceExtKt  */
fun Service.serviceScopeWithSource() = lazy { getScopeOrNull() ?: createScope(this) }

/** wraps org.koin.androidx.scope.LifecycleScopeDelegate - to add source  */
class LifecycleScopeWithSourceDelegate(
    val lifecycleOwner: LifecycleOwner,
    koinContext: KoinContext = GlobalContext,
    createScope: (Koin) -> Scope = { koin: Koin ->
        koin.createScope(
            lifecycleOwner.getScopeId(),
            lifecycleOwner.getScopeName(),
            lifecycleOwner
        )
    },
) : ReadOnlyProperty<LifecycleOwner, Scope> {

    private val _lifecycleDelegate = LifecycleScopeDelegate(lifecycleOwner, koinContext, createScope)

    override fun getValue(thisRef: LifecycleOwner, property: KProperty<*>): Scope {
        return _lifecycleDelegate.getValue(thisRef, property)
    }
}
于 2021-05-25T06:37:45.957 回答