Suppose I have a suspend function that provides an...
# koin
m
Suppose I have a suspend function that provides an instance of some interface. How can I use Koin to inject such an instance where required? Like mentioned https://github.com/InsertKoinIO/koin/issues/388
I’m thinking maybe the best way to go is for the instance to internally lazily perform some suspending init() rather than requiring the caller to explicitly do so.
a
can you be more explicit? 🤔
m
Suppose I have a singleton that requires a one time call to a suspending function
init()
before it can be used. Ideally any code that wants to use this singleton would call some suspending equivalent of
get()
(or somehow
by inject()
) in such a way that init() is called behind the scenes (presumably in some equivalent to single {} that takes a suspending lambda) only when necessary.
Currently, I do something like this:
Copy code
single(named("instanceProvider")) {
    suspendableLazy {
        createAndInitInstance()
    }
}
and then:
Copy code
private val instanceProvider by lazy {
   get<SuspendableProvider<MyClass>>(named("instanceProvider"))
}

suspend fun getInstance(): MyClass? = try {
    instanceProvider.get()
} catch (e: Exception) {
    Log.e("di", "unable to create instance", e)
    null
}
where using some common code:
Copy code
interface SuspendableProvider<T> {
    suspend fun get(): T
    val isCompleted: Boolean
}

fun <T> suspendableLazy(provider: suspend () -> T) = object : SuspendableProvider<T> {
    private val computed = GlobalScope.async(start = CoroutineStart.LAZY) { provider() }

    override val isCompleted: Boolean
        get() = computed.isCompleted

    override suspend fun get() = computed.await()
}
a
yeah, can be interesting to something in this way yes 👍
👍 1