是否可以在"懒惰"初始化程序中暂停-Coroutine?我得到错误"Android主循环线程中不允许运行阻止"

Ben*_*n H 4 kotlin kotlin-android-extensions kotlin-coroutines

我有很多我的应用程序正常使用"懒惰"初始化程序,因为一切都神奇地按照必要的顺序发生.

但并非所有初始化程序都是同步的.其中一些是包装回调,这意味着我需要等到回调发生,这意味着我需要runBlockingsuspendCoroutine.

但在重构​​一切后,我明白了 IllegalStateException: runBlocking is not allowed in Android main looper thread

什么?你不能阻止?你在这里杀了我.如果我的"偷懒"恰好是阻挡功能,那么正确的方法是什么?

private val cameraCaptureSession: CameraCaptureSession by lazy {
    runBlocking(Background) {
        suspendCoroutine { cont: Continuation<CameraCaptureSession> ->
            cameraDevice.createCaptureSession(Arrays.asList(readySurface, imageReader.surface), object : CameraCaptureSession.StateCallback() {
                override fun onConfigured(session: CameraCaptureSession) {
                    cont.resume(session).also {
                        Log.i(TAG, "Created cameraCaptureSession through createCaptureSession.onConfigured")
                    }
                }

                override fun onConfigureFailed(session: CameraCaptureSession) {
                    cont.resumeWithException(Exception("createCaptureSession.onConfigureFailed")).also {
                        Log.e(TAG, "onConfigureFailed: Could not configure capture session.")
                    }
                }
            }, backgroundHandler)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

该类的完整GIST,用于了解我最初想要实现的目标:https://gist.github.com/salamanders/aae560d9f72289d5e4b49011fd2ce62b

Mar*_*nik 5

众所周知,在UI线程上执行阻塞调用会导致在调用期间完全冻结应用程序.createCaptureSession具体国家的文件

完成会话配置可能需要几百毫秒,因为相机硬件可能需要打开电源或重新配置.

它可能很容易导致Application Not Responding对话框和您的应用程序被杀死.这就是为什么Kotlin runBlocking在UI线程上引入了明确的防范.

因此,当您已经尝试访问时,您的想法是及时启动此过程cameraCaptureSession无法工作.你必须做的是将访问它的代码包装进去launch(UI),然后把你val变成一个suspend fun.

简而言之:

private var savedSession: CameraCaptureSession? = null

private suspend fun cameraCaptureSession(): CameraCaptureSession {
    savedSession?.also { return it }
    return suspendCoroutine { cont ->
        cameraDevice.createCaptureSession(listOf(readySurface, imageReader.surface), object : CameraCaptureSession.StateCallback() {
            override fun onConfigured(session: CameraCaptureSession) {
                savedSession = session
                Log.i(TAG, "Created cameraCaptureSession through createCaptureSession.onConfigured")
                cont.resume(session)
            }

            override fun onConfigureFailed(session: CameraCaptureSession) {
                Log.e(TAG, "onConfigureFailed: Could not configure capture session.")
                cont.resumeWithException(Exception("createCaptureSession.onConfigureFailed"))
            }
        })
    }
}

fun useCamera() {
    launch(UI) {
        cameraCaptureSession().also { session ->
            session.capture(...)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这session.capture()是包装到的另一个目标suspend fun.

另外请务必注意,如果您确保cameraCaptureSession()在第一次呼叫恢复之前不再呼叫,我给出的代码是安全的.查看后续主题以获得更通用的解决方案.