在协程中切换到 UI 上下文

Nic*_*zzi 5 android kotlin kotlinx.coroutines

我是协程新手,我想知道是否可以将下面的代码从 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()
    }
Run Code Online (Sandbox Code Playgroud)

我当前活动代码的片段:

bikeAccessClient.startRent(bikeBLEName, BikeMode.HYBRID, object :
                    StartRentListener {
                    override fun onSuccess() {
                        runOnUiThread {
                            // UI update here
                        }
                    }
Run Code Online (Sandbox Code Playgroud)

Eug*_*nko 12

您可以使用withContext(Dispatchers.Main) {..}函数与其他协程调度程序一起执行部分代码。

kotlinx.coroutines.android包含函数的定义Dispatchers.Main,并与 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()
   } 

Run Code Online (Sandbox Code Playgroud)

块中的代码launch(Dispatchers.Main){..}在 UI 线程中执行。对startRent挂起函数的调用会挂起 UI 线程中的执行。一旦startRent准备好回复(来自后台线程),它就会恢复执行(由 完成并Dispatchers.Main相当于runOnUiThread {...})并从正确的线程执行 UI 更新

  • `Dispatchers.UI` 不存在(或者可能存在,但已弃用),它是 `Dispatchers.Main`。 (5认同)