1

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.

  • It seems from your code that you need to initialize onFooFired() before you create Library object with your callback, not only before calling library.bar(). – Orit Malki Jul 20 '20 at 06:38
  • @OritMalki, I've also tried to initialize it with an empty value `private var onFooFired: (Boolean) -> Unit = {}` and after that, it didn't throw an exception, but called this empty implementation. – Sergey Medgaus Jul 20 '20 at 06:46
  • sounds like it's the way to go. Or, if you have some constraints preventing you from initializing it before the Library, if the Library's callback is public or you have a method to add/set it to the library, initialize the library's callback before calling bar(). – Orit Malki Jul 20 '20 at 06:59

1 Answers1

1

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

Sergei Buvaka
  • 551
  • 1
  • 5
  • 16