为什么Kotlin中的某些GlobalScope.launch调用的内容默默地无法执行?

时间:2019-02-20 16:02:01

标签: android kotlin

我对Kotlin并不陌生-实际上,我从来都不打算使用它,但是我正在尝试使用CameraKit库,该库似乎使用了生成的Kotlin层作为其API接口。我一直在遇到无法正确断开相机的麻烦,有问题的代码(或者至少在我看来是最相关的部分)看起来像这样:

class CameraPreview : FrameLayout, CameraEvents {
    var TAG = "CameraPreview.kt"
    var lifecycleState: LifecycleState = LifecycleState.STOPPED
    var surfaceState: SurfaceState = SurfaceState.SURFACE_WAITING
    var cameraState: CameraState = CameraState.CAMERA_CLOSED
        set(state) {
            field = state
            when (state) {
                CameraState.CAMERA_OPENED -> {
                    listener?.onCameraOpened()
                }
                CameraState.PREVIEW_STARTED -> {
                    listener?.onPreviewStarted()
                }
                CameraState.PREVIEW_STOPPED -> {
                    listener?.onPreviewStopped()
                }
                CameraState.CAMERA_CLOSING -> {
                    listener?.onCameraClosed()
                }
                else -> {
                    // ignore
                }
            }
        }


    private val cameraDispatcher: CoroutineDispatcher = newSingleThreadContext("CAMERA")
    private var cameraOpenContinuation: Continuation<Unit>? = null
    private var previewStartContinuation: Continuation<Unit>? = null


    init {
        val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        displayOrientation = windowManager.defaultDisplay.rotation * 90

        cameraSurfaceView.cameraSurfaceTextureListener = object : CameraSurfaceTextureListener {
            override fun onSurfaceReady(cameraSurfaceTexture: CameraSurfaceTexture) {
                surfaceTexture = cameraSurfaceTexture
                surfaceState = SurfaceState.SURFACE_AVAILABLE
                if (lifecycleState == LifecycleState.STARTED || lifecycleState == LifecycleState.RESUMED) {
                    resume()
                }
            }
        }

        addView(cameraSurfaceView)
    }

    fun start(facing: CameraFacing) {
        GlobalScope.launch(cameraDispatcher) {
            runBlocking {
                Log.i(TAG, "Start preview state is "+lifecycleState)
                lifecycleState = LifecycleState.STARTED
                cameraFacing = facing
                openCamera()
            }
        }
    }

    fun resume() {
        GlobalScope.launch(cameraDispatcher) {
            runBlocking {
                Log.i("CameraPreview.kt", "Resume preview state is "+lifecycleState)
                lifecycleState = LifecycleState.RESUMED
                try {
                    startPreview()
                } catch (e: Exception) {
                    Log.i("CameraPreview.kt", "Start preview hit an exception: "+e.message)
                    // camera or surface not ready, wait.
                }
            }
        }
    }

    fun pause() {
        Log.i("CameraPreview.kt", "Pause called");
        GlobalScope.launch(cameraDispatcher) {
            Log.i(TAG, "Pause scope launched, runblocking call ahead.")
            runBlocking {
                Log.i("CameraPreview.kt", "Pause initiated, stop preview state is "+lifecycleState)
                lifecycleState = LifecycleState.PAUSED
                stopPreview()
            }  
        }

    }

    fun stop() {
        Log.i("CameraPreview.kt", "Stop called");
        GlobalScope.launch(cameraDispatcher) {
            Log.i(TAG, "Stop scope launched, runblocking call ahead.")
            runBlocking {
                Log.i("CameraPreview.kt", "Stop initiated, close camera state is "+lifecycleState)
                lifecycleState = LifecycleState.STOPPED
                closeCamera()
            }

        }

    }



    enum class CameraState {
        CAMERA_OPENING,
        CAMERA_OPENED,
        PREVIEW_STARTING,
        PREVIEW_STARTED,
        PREVIEW_STOPPING,
        PREVIEW_STOPPED,
        CAMERA_CLOSING,
        CAMERA_CLOSED;
    }

    // Camera control:

    private suspend fun openCamera(): Unit = suspendCoroutine {
        cameraOpenContinuation = it
        cameraState = CameraState.CAMERA_OPENING
        Log.i("CameraPreview.kt", "openCamera call state is "+lifecycleState)
        cameraApi.open(cameraFacing)
    }

    private suspend fun startPreview(): Unit = suspendCoroutine {
        Log.i("CameraPreview.kt", "startPreview, lifecyclestate "+ lifecycleState);
        // do stuff

    }

    private suspend fun stopPreview(): Unit = suspendCoroutine {
        Log.i("CameraPreview.kt", "Stop preview state is "+lifecycleState)
        cameraState = CameraState.PREVIEW_STOPPING
        cameraApi.stopPreview()
        it.resume(Unit)
    }

    private suspend fun closeCamera(): Unit = suspendCoroutine {
        Log.i("CameraPreview.kt", "Close camera state is "+lifecycleState)
        cameraState = CameraState.CAMERA_CLOSING
        cameraApi.release()
        it.resume(Unit)
    }


}

现在,当调用startresume时,它们将执行应有的操作。调用pausestop时,没有明显的变化,相机预览也不会暂停或停止。

我的日志记录表明,当调用pause()时,将记录初始调用,但是GlobalScope.launch(cameraDispatcher)内部的log语句永远不会出现。似乎GlobalScope只是将协同例程引入了虚空。在startresume正常工作的情况下,呼叫或调度程序似乎没有问题,但很难知道还有什么地方可以找到

如果我采用pausestop协同程序的内容并将其放在GlobalScope.launch之外以创建如下内容:

fun pause() {
    Log.i("CameraPreview.kt", "Pause called");
    GlobalScope.launch(cameraDispatcher) {
        Log.i(TAG, "Pause scope launched, runblocking call ahead.")
        runBlocking {
            Log.i("CameraPreview.kt", "Pause initiated, stop preview state is "+lifecycleState)
            lifecycleState = LifecycleState.PAUSED
            stopPreview()
        }
    }
    cameraState = CameraState.PREVIEW_STOPPING
    cameraApi.stopPreview()
}

现在它不仅可以工作,而且该协同例程也可以开始后续调用,好像被调用的内容以某种方式阻塞了它。运行Logcat时,我看不到任何错误消息。

这是我对Kotlin的首次介绍,因此我不确定该如何工作,但是似乎完全绕过基本代码可能不属于该规范。任何人都可以建议这里发生了什么,或者我如何找到问题的真正根源?

1 个答案:

答案 0 :(得分:1)

问题可能是您正在使用cameraDispatcher的共享单线程调度程序,然后使用runBlocking进行阻止。我不确定此代码基于什么,但是runBlocking在其文档中警告说,仅当在协程和严格的线程绑定执行(例如main或测试框架)之间桥接时才应使用该代码。

如果您删除对runBlocking的所有调用,您的代码仍然可以正常工作