Wait For Data Inside a Listener in a Coroutine

The first point is that I would change your loadData function into a suspending function instead of using launch. It's better to have the option to define at call site how you want to proceed with the execution. For example when implementing a test you may want to call your coroutine inside a runBlocking. You should also implement structured concurrency properly instead of relying on GlobalScope.

On the other side of the problem I would implement an extension function on the ThirdPartyLibrary that turns its async calls into a suspending function. This way you will ensure that the calling coroutine actually waits for the Library call to have some value in it.

Since we made loadData a suspending function we can now ensure that it will only start the new activity when the ThirdPartyLibrary call finishes.

import kotlinx.coroutines.*
import kotlin.coroutines.*

class InitialActivity : AppCompatActivity(), CoroutineScope {
    private lateinit var masterJob: Job
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + masterJob

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        masterJob = Job()
    }

    override fun onDestroy() {
        super.onDestroy()
        masterJob.cancel()
    }

    override fun onResume() {
        this.launch {
            val data = ThirdPartyLibrary().suspendLoadData()
            // TODO: act on data!
            startActivity(startNewIntent)
        }
    }
}

suspend fun ThirdPartyLibrary.suspendLoadData(): Data = suspendCoroutine { cont ->
    setOnDataListener(
            onSuccess = { cont.resume(it) },
            onFail = { cont.resumeWithException(it) }
    )
    startLoadingData()
}