CameraX:意外的旋转值 -1(在 API 22,Lollipop / 5.1 上)
CameraX: Unexpected rotation value -1 (on API 22, Lollipop / 5.1)
在 API 22 模拟器(Android 5.1 / Lollipop)上测试时使用 CameraX API
出现以下错误:
错误:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.cameraxtutorial, PID: 3815
java.lang.IllegalStateException: Unexpected rotation value -1
at androidx.camera.view.TransformUtils.surfaceRotationToRotationDegrees(TransformUtils.java:99)
at androidx.camera.view.PreviewTransformation.getTextureViewCorrectionMatrix(PreviewTransformation.java:156)
at androidx.camera.view.PreviewTransformation.transformView(PreviewTransformation.java:184)
at androidx.camera.view.PreviewViewImplementation.redrawPreview(PreviewViewImplementation.java:86)
at androidx.camera.view.PreviewViewImplementation.onSurfaceProvided(PreviewViewImplementation.java:93)
at androidx.camera.view.TextureViewImplementation.tryToProvidePreviewSurface(TextureViewImplementation.java:241)
at androidx.camera.view.TextureViewImplementation.onSurfaceTextureAvailable(TextureViewImplementation.java:139)
at android.view.TextureView.getHardwareLayer(TextureView.java:370)
at android.view.View.updateDisplayListIfDirty(View.java:14144)
at android.view.View.getDisplayList(View.java:14189)
at android.view.View.draw(View.java:14959)
at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
at android.view.View.draw(View.java:15234)
at android.widget.FrameLayout.draw(FrameLayout.java:598)
at android.view.View.updateDisplayListIfDirty(View.java:14167)
at android.view.View.getDisplayList(View.java:14189)
at android.view.View.draw(View.java:14959)
at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:1994)
at android.view.View.updateDisplayListIfDirty(View.java:14162)
at android.view.View.getDisplayList(View.java:14189)
at android.view.View.draw(View.java:14959)
at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
at android.view.View.updateDisplayListIfDirty(View.java:14162)
at android.view.View.getDisplayList(View.java:14189)
at android.view.View.draw(View.java:14959)
at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
at android.view.View.updateDisplayListIfDirty(View.java:14162)
at android.view.View.getDisplayList(View.java:14189)
at android.view.View.draw(View.java:14959)
at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
at android.view.View.updateDisplayListIfDirty(View.java:14162)
at android.view.View.getDisplayList(View.java:14189)
at android.view.View.draw(View.java:14959)
at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
at android.view.View.updateDisplayListIfDirty(View.java:14162)
at android.view.View.getDisplayList(View.java:14189)
at android.view.View.draw(View.java:14959)
at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
at android.view.View.draw(View.java:15234)
at android.widget.FrameLayout.draw(FrameLayout.java:598)
at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2650)
at android.view.View.updateDisplayListIfDirty(View.java:14167)
at android.view.View.getDisplayList(View.java:14189)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:273)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:279)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:318)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2530)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2352)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1982)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.vi
MainActivity.kt代码:
package com.cameraxtutorial
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.util.Size
import android.view.Surface
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import com.cameraxtutorial.databinding.ActivityMainBinding
import com.google.android.material.snackbar.Snackbar
import com.google.common.util.concurrent.ListenableFuture
import java.io.File
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
private lateinit var cameraSelector: CameraSelector
private var imageCapture: ImageCapture? = null
private lateinit var imgCaptureExecutor: ExecutorService
private val cameraPermissionResult =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { permissionGranted ->
if (permissionGranted) {
startCamera()
} else {
Snackbar.make(
binding.root,
"The camera permission is necessary",
Snackbar.LENGTH_INDEFINITE
).show()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
imgCaptureExecutor = Executors.newSingleThreadExecutor()
cameraPermissionResult.launch(android.Manifest.permission.CAMERA)
binding.imgCaptureBtn.setOnClickListener {
takePhoto()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
animateFlash()
}
}
binding.switchBtn.setOnClickListener {
cameraSelector = if (cameraSelector == CameraSelector.DEFAULT_BACK_CAMERA) {
CameraSelector.DEFAULT_FRONT_CAMERA
} else {
CameraSelector.DEFAULT_BACK_CAMERA
}
startCamera()
}
binding.galleryBtn.setOnClickListener {
val intent = Intent(this, GalleryActivity::class.java)
startActivity(intent)
}
}
private fun startCamera() {
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(binding.preview.surfaceProvider)
}
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
// imageCapture = ImageCapture.Builder().build()
imageCapture = ImageCapture.Builder().
// setTargetResolution(Size(960, 1280)).
// setTargetRotation(Surface.ROTATION_0).
build()
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
} catch (e: Exception) {
Log.d(TAG, "Use case binding failed")
}
}, ContextCompat.getMainExecutor(this))
}
private fun takePhoto() {
imageCapture?.let {
val fileName = "JPEG_${System.currentTimeMillis()}"+".jpg"
// val file = File(externalMediaDirs[0], fileName)
val file = File(applicationContext.filesDir, fileName)
val file_internal = File(applicationContext.filesDir, "aaa.png")
Log.e("file_internal", file_internal.path.toString())
Log.e("file_path", file.path.toString())
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(file).build()
it.takePicture(
outputFileOptions,
imgCaptureExecutor,
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
Log.i(TAG, "The image has been saved in ${file.toUri()}")
}
override fun onError(exception: ImageCaptureException) {
Toast.makeText(
binding.root.context,
"Error taking photo",
Toast.LENGTH_LONG
).show()
Log.d(TAG, "Error taking photo:$exception")
}
})
}
}
@RequiresApi(Build.VERSION_CODES.M)
private fun animateFlash() {
binding.root.postDelayed({
binding.root.foreground = ColorDrawable(Color.WHITE)
binding.root.postDelayed({
binding.root.foreground = null
}, 50)
}, 100)
}
companion object {
val TAG = "MainActivity"
}
}
Gradle 应用程序:
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdk 31
defaultConfig {
applicationId "com.cameraxtutorial"
minSdk 21
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
buildFeatures{
viewBinding true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
// def camerax_version = "1.0.1"
def camerax_version = "1.2.0-alpha01"
// CameraX core library using camera2 implementation
implementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX Lifecycle Library
implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class
implementation "androidx.camera:camera-view:1.0.0-alpha27"
implementation 'com.github.bumptech.glide:glide:4.12.0'
}
这个 app/Activity 在 Android 11 或 API 30 上运行良好,CameraX 文档说它支持 API 21 - 最近的 APIs,任何帮助将不胜感激。
您的 CameraX 库版本不匹配。 1.2.0-alpha01
v.s。 1.0.0-alpha27
def camerax_version = "1.2.0-alpha01"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:1.0.0-alpha27"
我假设 gradle 解析 camera-core
和 camera-view
使用不同的版本,这导致了问题。要解决此问题,您可以使用 1.2.0-alpha01
获取最新的 alpha 版或使用 1.1.0-rc01
获取更稳定的版本。
在 API 22 模拟器(Android 5.1 / Lollipop)上测试时使用 CameraX API
出现以下错误:
错误:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.cameraxtutorial, PID: 3815 java.lang.IllegalStateException: Unexpected rotation value -1 at androidx.camera.view.TransformUtils.surfaceRotationToRotationDegrees(TransformUtils.java:99) at androidx.camera.view.PreviewTransformation.getTextureViewCorrectionMatrix(PreviewTransformation.java:156) at androidx.camera.view.PreviewTransformation.transformView(PreviewTransformation.java:184) at androidx.camera.view.PreviewViewImplementation.redrawPreview(PreviewViewImplementation.java:86) at androidx.camera.view.PreviewViewImplementation.onSurfaceProvided(PreviewViewImplementation.java:93) at androidx.camera.view.TextureViewImplementation.tryToProvidePreviewSurface(TextureViewImplementation.java:241) at androidx.camera.view.TextureViewImplementation.onSurfaceTextureAvailable(TextureViewImplementation.java:139) at android.view.TextureView.getHardwareLayer(TextureView.java:370) at android.view.View.updateDisplayListIfDirty(View.java:14144) at android.view.View.getDisplayList(View.java:14189) at android.view.View.draw(View.java:14959) at android.view.ViewGroup.drawChild(ViewGroup.java:3405) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198) at android.view.View.draw(View.java:15234) at android.widget.FrameLayout.draw(FrameLayout.java:598) at android.view.View.updateDisplayListIfDirty(View.java:14167) at android.view.View.getDisplayList(View.java:14189) at android.view.View.draw(View.java:14959) at android.view.ViewGroup.drawChild(ViewGroup.java:3405) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198) at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:1994) at android.view.View.updateDisplayListIfDirty(View.java:14162) at android.view.View.getDisplayList(View.java:14189) at android.view.View.draw(View.java:14959) at android.view.ViewGroup.drawChild(ViewGroup.java:3405) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198) at android.view.View.updateDisplayListIfDirty(View.java:14162) at android.view.View.getDisplayList(View.java:14189) at android.view.View.draw(View.java:14959) at android.view.ViewGroup.drawChild(ViewGroup.java:3405) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198) at android.view.View.updateDisplayListIfDirty(View.java:14162) at android.view.View.getDisplayList(View.java:14189) at android.view.View.draw(View.java:14959) at android.view.ViewGroup.drawChild(ViewGroup.java:3405) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198) at android.view.View.updateDisplayListIfDirty(View.java:14162) at android.view.View.getDisplayList(View.java:14189) at android.view.View.draw(View.java:14959) at android.view.ViewGroup.drawChild(ViewGroup.java:3405) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198) at android.view.View.updateDisplayListIfDirty(View.java:14162) at android.view.View.getDisplayList(View.java:14189) at android.view.View.draw(View.java:14959) at android.view.ViewGroup.drawChild(ViewGroup.java:3405) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198) at android.view.View.draw(View.java:15234) at android.widget.FrameLayout.draw(FrameLayout.java:598) at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2650) at android.view.View.updateDisplayListIfDirty(View.java:14167) at android.view.View.getDisplayList(View.java:14189) at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:273) at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:279) at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:318) at android.view.ViewRootImpl.draw(ViewRootImpl.java:2530) at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2352) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1982) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767) at android.vi
MainActivity.kt代码:
package com.cameraxtutorial
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.util.Size
import android.view.Surface
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import com.cameraxtutorial.databinding.ActivityMainBinding
import com.google.android.material.snackbar.Snackbar
import com.google.common.util.concurrent.ListenableFuture
import java.io.File
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
private lateinit var cameraSelector: CameraSelector
private var imageCapture: ImageCapture? = null
private lateinit var imgCaptureExecutor: ExecutorService
private val cameraPermissionResult =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { permissionGranted ->
if (permissionGranted) {
startCamera()
} else {
Snackbar.make(
binding.root,
"The camera permission is necessary",
Snackbar.LENGTH_INDEFINITE
).show()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
imgCaptureExecutor = Executors.newSingleThreadExecutor()
cameraPermissionResult.launch(android.Manifest.permission.CAMERA)
binding.imgCaptureBtn.setOnClickListener {
takePhoto()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
animateFlash()
}
}
binding.switchBtn.setOnClickListener {
cameraSelector = if (cameraSelector == CameraSelector.DEFAULT_BACK_CAMERA) {
CameraSelector.DEFAULT_FRONT_CAMERA
} else {
CameraSelector.DEFAULT_BACK_CAMERA
}
startCamera()
}
binding.galleryBtn.setOnClickListener {
val intent = Intent(this, GalleryActivity::class.java)
startActivity(intent)
}
}
private fun startCamera() {
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(binding.preview.surfaceProvider)
}
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
// imageCapture = ImageCapture.Builder().build()
imageCapture = ImageCapture.Builder().
// setTargetResolution(Size(960, 1280)).
// setTargetRotation(Surface.ROTATION_0).
build()
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
} catch (e: Exception) {
Log.d(TAG, "Use case binding failed")
}
}, ContextCompat.getMainExecutor(this))
}
private fun takePhoto() {
imageCapture?.let {
val fileName = "JPEG_${System.currentTimeMillis()}"+".jpg"
// val file = File(externalMediaDirs[0], fileName)
val file = File(applicationContext.filesDir, fileName)
val file_internal = File(applicationContext.filesDir, "aaa.png")
Log.e("file_internal", file_internal.path.toString())
Log.e("file_path", file.path.toString())
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(file).build()
it.takePicture(
outputFileOptions,
imgCaptureExecutor,
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
Log.i(TAG, "The image has been saved in ${file.toUri()}")
}
override fun onError(exception: ImageCaptureException) {
Toast.makeText(
binding.root.context,
"Error taking photo",
Toast.LENGTH_LONG
).show()
Log.d(TAG, "Error taking photo:$exception")
}
})
}
}
@RequiresApi(Build.VERSION_CODES.M)
private fun animateFlash() {
binding.root.postDelayed({
binding.root.foreground = ColorDrawable(Color.WHITE)
binding.root.postDelayed({
binding.root.foreground = null
}, 50)
}, 100)
}
companion object {
val TAG = "MainActivity"
}
}
Gradle 应用程序:
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdk 31
defaultConfig {
applicationId "com.cameraxtutorial"
minSdk 21
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
buildFeatures{
viewBinding true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
// def camerax_version = "1.0.1"
def camerax_version = "1.2.0-alpha01"
// CameraX core library using camera2 implementation
implementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX Lifecycle Library
implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class
implementation "androidx.camera:camera-view:1.0.0-alpha27"
implementation 'com.github.bumptech.glide:glide:4.12.0'
}
这个 app/Activity 在 Android 11 或 API 30 上运行良好,CameraX 文档说它支持 API 21 - 最近的 APIs,任何帮助将不胜感激。
您的 CameraX 库版本不匹配。 1.2.0-alpha01
v.s。 1.0.0-alpha27
def camerax_version = "1.2.0-alpha01"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:1.0.0-alpha27"
我假设 gradle 解析 camera-core
和 camera-view
使用不同的版本,这导致了问题。要解决此问题,您可以使用 1.2.0-alpha01
获取最新的 alpha 版或使用 1.1.0-rc01
获取更稳定的版本。