Sergey Medgaus
Sergey Medgaus

Reputation: 33

Converting a callback to a suspendCoroutine, when the callback is a field of class

I want to convert some 3rd-party API based on callbacks to simple suspend functions that are easy to use. Here's a simplified example of mine implementation.

class LibraryWrapper {

    private lateinit var onFooFired: (Boolean) -> Unit

    private val libraryCallback = object : LibraryCallback {
        override fun foo(result: Boolean) {
            onFooFired(result)
        }
    }
    private val library = Library(libraryCallback)

    suspend fun bar(): Boolean {
        return suspendCoroutine { performingBar: Continuation<Boolean> ->
            onFooFired = {fooResult -> performingBar.resume(fooResult) }
            library.bar()
        }
    }
}

But this solution sometimes works and sometimes not. There is such an issue with this lambda field, that sometimes it initializes correctly, but sometimes the exception is thrown that "lateinit property onFooFired is not initialized".

It's very strange because I do initialize it before run library.bar() and foo of LibraryCallback is called only after library.bar() was called.

Upvotes: 1

Views: 504

Answers (1)

Sergei Buvaka
Sergei Buvaka

Reputation: 611

first of all, I think it is not a good approach to use "lateinit var" when you don't control the initialization of a field. Use lateinit only when you have the promise of initialization.

Try to use nullable field implementation like

private var onFooFired: ((Boolean) -> Unit)? = null

and in callback :

private val libraryCallback = object : LibraryCallback {
        override fun foo(result: Boolean) {
            onFooFired?.invoke(result)
        }
    }

In this case, until you do not have an implementation of "onFooFired" lambda, it does not invoke

Upvotes: 1

Related Questions