我是协程新手,我想知道是否可以从以下代码的coroutineScope(GlobalScope)切换到UI范围。我的问题是,协程启动体内的步骤必须在辅助线程中执行,否则侦听器通知必须在ui线程中执行,以避免在我的活动代码中调用runOnUiThread。
override suspend fun startRent(name: String, bikeMode: BikeMode, listener: StartRentListener) {
var bleDevice : RxBleDevice
val scanFilter: ScanFilter = ScanFilter.Builder().setDeviceName(name).build()
val scanSettings: ScanSettings = ScanSettings.Builder().build()
val job = GlobalScope.launch {
try {
bleDevice = rxBleClient.scanBleDevicesExt(rxBleClient, scanSettings, scanFilter)
val bleConnection = bleDevice.establishConnectionExt()
// write handshake
connectionManager.writeHandshake(bleDevice, bleConnection)
// open lock
openLock(bleDevice, bikeMode, bleConnection)
// getting user position
apiHelper.sendLockRequest(bleDevice.name, getPosition())
bleDevice.disconnect()
// this should be called on main thread once all the previous operations are finished
listener.onSuccess()
} catch (e: Exception) {
listener.onError(e)
}
}
job.join()
}
我当前活动代码的摘录:
bikeAccessClient.startRent(bikeBLEName, BikeMode.HYBRID, object :
StartRentListener {
override fun onSuccess() {
runOnUiThread {
// UI update here
}
}
答案 0 :(得分:1)
您可以使用withContext(Dispatchers.UI) {..}
函数与另一个Coroutine Dispatcher一起执行部分代码。
kotlinx.coroutines.android
包含Dispatchers.UI
函数的定义,并且已与Android UI正确集成。
在您的代码中使用显式分派器非常容易出错。取而代之,我建议在设计代码时减少明确的要求。
我会这样写:
fun uiActionHandlerToStartTheProcess() {
launch(Dispatchers.Main) {
val result = startRent(...) // no callback here, suspend function
//UI Update Here
}
}
suspend fun CoroutineScope.startRent() : SomeResultOfWork {
//that function offloads the execution to a IO (aka brackground) thread
return withContext(Dispatchers.IO){
//here goes your code from `startRent`
//use `suspendCancellableCoroutine {cont -> .. }` if you need to handle callbacks from it
SomeResultOfWork()
}
launch(Dispatchers.Main){..}
块中的代码在UI线程中执行。对startRent
暂停函数的调用将在UI线程中暂停执行。 startRent
准备好了(来自后台线程)的回复后,它将继续执行(由Dispatchers.Main
完成并等效于runOnUiThread {...}
),并从右螺纹