Я новичок в 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)
}
}
Теперь, когда start
и resume
называются, они делают то, что должны.При вызове pause
и stop
ощутимых изменений не происходит, и предварительный просмотр камеры не приостанавливается и не останавливается.
Моя запись в журнале указывает, что при вызове pause()
первоначальный вызов регистрируется, нооператор журнала внутри GlobalScope.launch(cameraDispatcher)
никогда не появляется.Кажется, что GlobalScope просто запускает подпрограмму в пустоту.Поскольку start
и resume
работают, кажется, что нет проблем с вызовом или диспетчером, но трудно знать, где еще искать
Если я возьму содержимоеpause
или stop
подпрограмма и поместите ее вне 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, поэтому я не совсем уверен, как он должен работать, но кажется, что полный обход существенного кода может не сработать.быть частью спецификации.Кто-нибудь может подсказать, что здесь происходит или как я могу отследить истинный источник проблемы?