I’m having issue with ```override val scope: Scope...
# koin
a
I’m having issue with
Copy code
override val scope: Scope by lazy { koin.createScope(scopeID, getScopeName(), this) }
in my child fragment which extends from
ScopeFragment
. For some reason it gives me else condition and exception
NoScopeDefFoundException
from
onViewCreated
method.
Copy code
val scopeDefinition = _scopeDefinitions[qualifier.value]
        return if (scopeDefinition != null) {
            val createdScope: Scope = createScope(scopeId, scopeDefinition, source)
            _scopes[scopeId] = createdScope
            createdScope
        } else {
            throw NoScopeDefFoundException("No Scope Definition found for qualifer '${qualifier.value}'")
        }
Should I declare each fragment scope in my module before I can use or why I could get this error in
2.2.0-beta-1
version? Also it seem to call
createScope
and fail in
onViewCreated
because of this line
Copy code
koin._logger.debug("Open fragment scope: $scope")
in
ScopeFragment
Update: after a bit of tries. If I declare scope for a fragment like this
Copy code
scope(named<ChildFragment>()) {  }
It still not work, but I remember it was mentioned that empty declarations will not be allowed… so it works it I declare something scoped
Copy code
scope(named<ChildFragment>()) {
    scoped { (activity: BaseActivity) -> CustomTabsHelper(activity) }
}
But this is very weird that I have to declare scope before the fragment
createScope
. My assumption was that each
ScopeFragment
is able to create its own scope and I can use that scope anytime I need it. Since all my fragment as extended from the same BaseFragment or similar. This is very unusable since I can’t extend from
ScopeFragment
only on some of them. From other hand declaring useless scopes in modules for each and every fragment I have this is even more work. Not sure what was the idea behind this change. With lifecycle it was much easier (like is it if you need it or just skip it). As usual any feedback or discussions are welcome 😄 Koin is the best anyway 🤟
s
Hi Vitali, I’m having a hard time understanding the context in which you are and your problem.
in my child fragment
do you have nested fragments ? if you use
ScopeFragment
declare a
Copy code
scope<ChildFragment { 
// you needs something here
 }
I have
Copy code
factory { DumyDef() }
Copy code
internal class DumyDef
a
You got it right. If I will define scope and declare something inside the scope it will work. But all my fragments extend from the parent fragment and if I want some of the fragment to use scope API, I have to change parent class of my base fragment class, which leads to the situation I mentioned above as well. I have to declare
scope
for each and every fragment that will subclass my base fragment class. It looks like I need to avoid using
ScopeFragment
for now and just use an Activity and get all the required instances from the parent activity.
@arnaud.giuliani is it possible to use
ScopeFragment
but making the scope it creates optional. I’m having lots of component fragments which are using shared VM from
ScopeActivity
and I have my activity subclass it. Sometimes those fragments are using their scope for creating their own modules etc, but mostly they are not. It seems I could not use only
ScopeActivity
and I have to use
ScopeFragment
as well in order to get scope of the activity correctly. But right now I have to declare each and every fragment inside module in order to avoid crash during fragment initialization. I posted this before here as well, but not sure if you saw it or not. The information about the crash I mentioned you can find in my post above in this thread.
s
Wy do you use a ScopeFragment if you don’t need a scope ?
a
because without it I cannot get
requireScopeActivity
and get shared instance of VM from its scope
s
so you directly access the objects of your Activity in your fragment (not in a class used by the fragment)?
a
I’m accessing activity scope like this
requireScopeActivity<ProcessActivity>().getViewModel()
a
Hi, why the standard
requireActivity()
is not enough then?
I’m ok to check if we can let the Scope empty or something to help declaration with that
👍 1
a
you have to cast etc… I’m trying to understand how
ScopeActivity
and
ScopeFragment
meant to be used. And why
requireScopeActivity
is needed etc. Current I workaround it with creating my own
ScopeFragment
copy by wrapping the log calls with try. Which solves the issue.
s
if you just access the viewModel you can just access it through the activity, there is no scoping involved here
a
I know that… I’m trying to understand why/how the new classes meant to be used. In order to use them correctly. Previously I have been using
viewModel<SomeVM>()
in activity and call the
sharedViewModel
inside my fragments and that worked well, with new version I could not do that anymore, thats why I’m trying to figure out how should I deal now with similar scenarios.
a
with new version I could not do that anymore
You don’t have to use ScopeFragment or ScopeActivity if you don’t use scopes at all
those classes are there to automatically create scopes for you ... else non need to use them
a
lol, yes. It looks like I confused myself with imports for
getSharedViewModel
. Just found it now again 😄 . But have an ability to subclass
ScopeFragment
without requirement for creating the scope is still valid. Since if I have the parent fragment for most of my component fragments to reuse core logic. And some of those fragment might need the fragment scope. But since they all have to subclass base fragment, I can’t extend the
ScopeFragment
for some of them. Anyway, thanks for your responses and Koin is 🚀
💪 1
a
I can check if scope creation can be lazy
or at least, checked with boolean
a
I made it like this
Copy code
abstract class OptionalScopeFragment(
    @LayoutRes contentLayoutId: Int = 0
) : Fragment(contentLayoutId), KoinScopeComponent {

    override val koin by lazy { getKoin() }
    override val scope: Scope by lazy { createScope() }

    private var hasScopeDefinition = false

    val scopeActivity: ScopeActivity?
        get() = activity as? ScopeActivity

    inline fun <reified T : ScopeActivity> requireScopeActivity(): T = activity as? T
        ?: error("can't get ScopeActivity ${T::class}")

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        hasScopeDefinition = try {
            koin.logger.debug("Open fragment scope: $scope")
            true
        } catch (e: NoScopeDefFoundException) {
            logw { "koin:: could not open the scope for ${this.javaClass.name}" }
            false
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        if (hasScopeDefinition) {
            koin.logger.debug("Close fragment scope: $scope")
            scope.close()
        }
    }
}
Might be ugly but works 😄
a
houla 😄
I’ll keep an eye on that 👍