Ожидание данных внутри слушателя в сопрограмме - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть сопрограмма, которую я хотел бы запустить при запуске Android во время заставки. Я хотел бы подождать, пока данные вернутся, прежде чем я начну следующее действие. Каков наилучший способ сделать это? В настоящее время наш андроид использует экспериментальные сопрограммы 0.26.0 ... пока не могу это изменить.

ОБНОВЛЕНО: теперь мы используем последние сопрограммы и больше не экспериментальные

onResume() {
    loadData()
}

fun loadData() = GlobalScope.launch {
    val job = GlobalScope.async {
        startLibraryCall()
    }
    // TODO await on success
    job.await()
    startActivity(startnewIntent)
}

fun startLibraryCall() {
    val thirdPartyLib() = ThirdPartyLibrary()
    thirdPartyLib.setOnDataListener() { 
        ///psuedocode for success/ fail listeners
        onSuccess -> ///TODO return data
        onFail -> /// TODO return other data
    }
}

Ответы [ 2 ]

0 голосов
/ 06 ноября 2018

Вы можете использовать LiveData

liveData.value = job.await()

А затем добавить в onCreate (), например,

liveData.observe(currentActivity, observer)

В обозревателе просто подождите, пока значение не станет нулевым, а затем начните новое действие

Observer { result ->
            result?.let { 
                startActivity(newActivityIntent)
            } 
}
0 голосов
/ 06 ноября 2018

Во-первых, я бы изменил вашу функцию loadData на функцию приостановки вместо использования launch. Лучше иметь возможность определить на сайте вызова, как вы хотите продолжить выполнение. Например, при выполнении теста вы можете назвать свою сопрограмму внутри runBlocking. Вы также должны правильно реализовать структурированный параллелизм вместо того, чтобы полагаться на GlobalScope.

С другой стороны проблемы я бы реализовал функцию расширения на ThirdPartyLibrary, которая превращает его асинхронные вызовы в функцию приостановки. Таким образом вы обеспечите, чтобы вызывающая сопрограмма действительно ожидала, чтобы в вызове библиотеки было какое-то значение.

Поскольку мы сделали loadData приостановленной функцией, теперь мы можем гарантировать, что она начнет новую деятельность только после завершения вызова ThirdPartyLibrary.

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()
}
...