Android CameraX在ImageCapture后停止片段时引发异常
高级概述:我正在尝试捕获一张照片,并在成功捕获图像后返回上一屏幕 由于某些原因,在导航回时,会引发几个与CameraX相关的异常Android CameraX在ImageCapture后停止片段时引发异常,android,kotlin,android-lifecycle,android-camerax,Android,Kotlin,Android Lifecycle,Android Camerax,高级概述:我正在尝试捕获一张照片,并在成功捕获图像后返回上一屏幕 由于某些原因,在导航回时,会引发几个与CameraX相关的异常 2020-12-26 19:00:43.740 8218-8218/com.webslinger.dejavu E/TakePictureUseCase$execute: Photo capture failed: Camera is closed. androidx.camera.core.ImageCaptureException: Camera is c
2020-12-26 19:00:43.740 8218-8218/com.webslinger.dejavu E/TakePictureUseCase$execute: Photo capture failed: Camera is closed.
androidx.camera.core.ImageCaptureException: Camera is closed.
at androidx.camera.core.ImageCapture$ImageCaptureRequest.lambda$notifyCallbackError$1$ImageCapture$ImageCaptureRequest(ImageCapture.java:2232)
at androidx.camera.core.-$$Lambda$ImageCapture$ImageCaptureRequest$KlqAxzwB-08wcOFrjThjf8ncF2g.run(Unknown Source:8)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:205)
at android.app.ActivityThread.main(ActivityThread.java:6991)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:884)
Caused by: androidx.camera.core.CameraClosedException: Camera is closed.
at androidx.camera.core.ImageCapture.abortImageCaptureRequests(ImageCapture.java:809)
at androidx.camera.core.ImageCapture.onStateDetached(ImageCapture.java:805)
at androidx.camera.camera2.internal.Camera2CameraImpl.notifyStateDetachedToUseCases(Camera2CameraImpl.java:732)
at androidx.camera.camera2.internal.Camera2CameraImpl.detachUseCases(Camera2CameraImpl.java:767)
at androidx.camera.core.internal.CameraUseCaseAdapter.detachUseCases(CameraUseCaseAdapter.java:280)
at androidx.camera.lifecycle.LifecycleCamera.onStop(LifecycleCamera.java:93)
at androidx.camera.lifecycle.LifecycleCamera.suspend(LifecycleCamera.java:119)
at androidx.camera.lifecycle.LifecycleCameraRepository.suspendUseCases(LifecycleCameraRepository.java:433)
at androidx.camera.lifecycle.LifecycleCameraRepository.setInactive(LifecycleCameraRepository.java:387)
at androidx.camera.lifecycle.LifecycleCameraRepository$LifecycleCameraRepositoryObserver.onStop(LifecycleCameraRepository.java:504)
at java.lang.reflect.Method.invoke(Native Method)
at androidx.lifecycle.ClassesInfoCache$MethodReference.invokeCallback(ClassesInfoCache.java:219)
at androidx.lifecycle.ClassesInfoCache$CallbackInfo.invokeMethodsForEvent(ClassesInfoCache.java:194)
at androidx.lifecycle.ClassesInfoCache$CallbackInfo.invokeCallbacks(ClassesInfoCache.java:185)
at androidx.lifecycle.ReflectiveGenericLifecycleObserver.onStateChanged(ReflectiveGenericLifecycleObserver.java:37)
at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
at androidx.lifecycle.LifecycleRegistry.backwardPass(LifecycleRegistry.java:284)
at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:302)
at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:148)
at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:134)
at androidx.fragment.app.FragmentViewLifecycleOwner.handleLifecycleEvent(FragmentViewLifecycleOwner.java:62)
at androidx.fragment.app.Fragment.performStop(Fragment.java:3166)
at androidx.fragment.app.FragmentStateManager.stop(FragmentStateManager.java:630)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:324)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2168)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2094)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1990)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:205)
at android.app.ActivityThread.main(ActivityThread.java:6991)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:884)
2020-12-26 19:00:43.745 8218-8218/com.webslinger.dejavu E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.webslinger.dejavu, PID: 8218
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:503)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:884)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:884)
Caused by: androidx.camera.core.ImageCaptureException: Camera is closed.
at androidx.camera.core.ImageCapture$ImageCaptureRequest.lambda$notifyCallbackError$1$ImageCapture$ImageCaptureRequest(ImageCapture.java:2232)
at androidx.camera.core.-$$Lambda$ImageCapture$ImageCaptureRequest$KlqAxzwB-08wcOFrjThjf8ncF2g.run(Unknown Source:8)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:205)
at android.app.ActivityThread.main(ActivityThread.java:6991)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:884)
Caused by: androidx.camera.core.CameraClosedException: Camera is closed.
at androidx.camera.core.ImageCapture.abortImageCaptureRequests(ImageCapture.java:809)
at androidx.camera.core.ImageCapture.onStateDetached(ImageCapture.java:805)
at androidx.camera.camera2.internal.Camera2CameraImpl.notifyStateDetachedToUseCases(Camera2CameraImpl.java:732)
at androidx.camera.camera2.internal.Camera2CameraImpl.detachUseCases(Camera2CameraImpl.java:767)
at androidx.camera.core.internal.CameraUseCaseAdapter.detachUseCases(CameraUseCaseAdapter.java:280)
at androidx.camera.lifecycle.LifecycleCamera.onStop(LifecycleCamera.java:93)
at androidx.camera.lifecycle.LifecycleCamera.suspend(LifecycleCamera.java:119)
at androidx.camera.lifecycle.LifecycleCameraRepository.suspendUseCases(LifecycleCameraRepository.java:433)
at androidx.camera.lifecycle.LifecycleCameraRepository.setInactive(LifecycleCameraRepository.java:387)
at androidx.camera.lifecycle.LifecycleCameraRepository$LifecycleCameraRepositoryObserver.onStop(LifecycleCameraRepository.java:504)
at java.lang.reflect.Method.invoke(Native Method)
at androidx.lifecycle.ClassesInfoCache$MethodReference.invokeCallback(ClassesInfoCache.java:219)
at androidx.lifecycle.ClassesInfoCache$CallbackInfo.invokeMethodsForEvent(ClassesInfoCache.java:194)
at androidx.lifecycle.ClassesInfoCache$CallbackInfo.invokeCallbacks(ClassesInfoCache.java:185)
at androidx.lifecycle.ReflectiveGenericLifecycleObserver.onStateChanged(ReflectiveGenericLifecycleObserver.java:37)
at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
at androidx.lifecycle.LifecycleRegistry.backwardPass(LifecycleRegistry.java:284)
at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:302)
at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:148)
at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:134)
at androidx.fragment.app.FragmentViewLifecycleOwner.handleLifecycleEvent(FragmentViewLifecycleOwner.java:62)
at androidx.fragment.app.Fragment.performStop(Fragment.java:3166)
at androidx.fragment.app.FragmentStateManager.stop(FragmentStateManager.java:630)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:324)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2168)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2094)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1990)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
我只在开始预览用例后测试了向后导航,没有问题,所以我认为问题与捕获用例有关
我还尝试在退出片段之前手动解除绑定用例,尽管这应该是不必要的,因为相机用例绑定到片段的生命周期
我是这个图书馆的新手,任何想法都将不胜感激
class TakeAfterPictureFragment : BaseFragment() {
private lateinit var dataBinding: TakeAfterPictureFragmentBinding
private lateinit var viewModel: TakeAfterPictureViewModel
@Inject
lateinit var viewModelFactory: TakeAfterPictureViewModelFactory
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View{
dataBinding = DataBindingUtil.inflate(
inflater,
R.layout.take_after_picture_fragment,
container,
false
)
return dataBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
inject(this)
viewModel = ViewModelProvider(
this,
viewModelFactory
).get(TakeAfterPictureViewModel::class.java)
loadBeforePicture()
checkCameraPermissions()
bindCameraCaptureButton()
bindOnPhotoCaptured()
}
private fun loadBeforePicture() {
arguments?.let {
val beforePictureUri: Uri = it.get("BEFORE_PICTURE_PATH") as Uri
Glide.with(this)
.load(beforePictureUri)
.into(dataBinding.beforePictureOverlay)
}
dataBinding.beforePictureOverlay.imageAlpha = 70
}
private fun checkCameraPermissions() {
if (allPermissionsGranted()) {
viewModel.startCameraPreview(viewLifecycleOwner, dataBinding.viewFinder.surfaceProvider)
} else {
ActivityCompat.requestPermissions(
requireActivity(), REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
)
}
}
private fun bindCameraCaptureButton() {
dataBinding.cameraCaptureButton.setOnClickListener {
viewModel.takeAfterPicture()
}
}
private fun bindOnPhotoCaptured(){
viewModel.photoUri.observe(viewLifecycleOwner, Observer {
Toast.makeText(requireContext(), "Photo capture successful.", Toast.LENGTH_LONG).show()
viewModel.navigateBack(screenNavigator)
})
}
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String>, grantResults:
IntArray
) {
if (requestCode == REQUEST_CODE_PERMISSIONS) {
if (allPermissionsGranted()) {
viewModel.startCameraPreview(viewLifecycleOwner, dataBinding.viewFinder.surfaceProvider)
} else {
showPermissionsNotGrantedMessage()
viewModel.navigateBack(screenNavigator)
}
}
}
private fun showPermissionsNotGrantedMessage() {
Toast.makeText(
requireContext(),
"Permissions not granted by the user.",
Toast.LENGTH_SHORT
).show()
}
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(
requireContext(), it
) == PackageManager.PERMISSION_GRANTED
}
override fun onDestroy() {
super.onDestroy()
}
companion object {
fun newInstance() = TakeAfterPictureFragment()
private const val REQUEST_CODE_PERMISSIONS = 10
private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
}
类TakeAfterPictureFragment:BaseFragment(){
私有lateinit变量数据绑定:TakeAfterPictureFragmentBinding
私有lateinit变量viewModel:TakeAfterPictureViewModel
@注入
lateinit变量viewModelFactory:TakeAfterPictureViewModelFactory
覆盖创建视图(
充气器:布局充气器,容器:视图组?,
savedInstanceState:捆绑?
):查看{
数据绑定=数据绑定直到充气(
充气机,
R.layout.在图片片段之后拍摄,
集装箱,
假的
)
return dataBinding.root
}
覆盖已创建的视图(视图:视图,保存状态:捆绑?){
super.onViewCreated(视图,savedInstanceState)
注入(这个)
viewModel=ViewModelProvider(
这
viewModelFactory
).get(TakeAfterPictureViewModel::class.java)
loadBeforePicture()
checkCameraPermissions()
bindCameraCaptureButton()
bindOnPhotoCaptured()
}
私人娱乐加载预览图片(){
争论?让我们{
val beforeepictureuri:Uri=it.get(“BEFORE\u PICTURE\u PATH”)作为Uri
用(这个)滑翔
.加载(在图像之前)
.into(数据绑定。图片覆盖前)
}
dataBinding.beforePictureOverlay.imageAlpha=70
}
私人娱乐checkCameraPermissions(){
如果(allPermissionsGranted()){
viewModel.startCameraPreview(viewLifecycleOwner、数据绑定、取景器、surfaceProvider)
}否则{
ActivityCompat.requestPermissions(
Requiresponsibility()、所需权限、请求代码权限
)
}
}
private fun bindCameraCaptureButton(){
dataBinding.cameraCaptureButton.setOnClickListener{
viewModel.takeAfterPicture()
}
}
私人娱乐bindOnPhotoCaptured(){
viewModel.photoUri.observe(viewLifecycleOwner,Observer{
Toast.makeText(requireContext(),“照片捕获成功”,Toast.LENGTH\u LONG.show())
viewModel.navigateBack(屏幕导航器)
})
}
覆盖onRequestPermissionsResult(
请求代码:Int,权限:数组,GrantResult:
无阵列
) {
if(requestCode==请求\代码\权限){
如果(allPermissionsGranted()){
viewModel.startCameraPreview(viewLifecycleOwner、数据绑定、取景器、surfaceProvider)
}否则{
showPermissionsNotGrandedMessage()
viewModel.navigateBack(屏幕导航器)
}
}
}
私人娱乐节目许可证snotgrandedMessage(){
Toast.makeText(
requireContext(),
“用户未授予权限。”,
吐司长度
).show()
}
private fun allPermissionsGranted()=必需的权限。全部{
ContextCompat.checkSelfPermission(
requireContext(),它
)==已授予PackageManager.PERMISSION\u权限
}
重写onDestroy(){
super.ondestory()
}
伴星{
fun newInstance()=TakeAfterPictureFragment()
私有const val请求\代码\权限=10
private val REQUIRED_PERMISSIONS=arrayOf(Manifest.permission.CAMERA)
}
}
class takeafterPictureView模型(
私人val takePictureUseCase:takePictureUseCase,
专用val outputDirectoryProvider:PhotoOutputDirectoryProvider,
私人摄像机:伊卡梅拉,
私人val执行人:执行人
):ViewModel(){
私有val_photoUri:MutableLiveData=MutableLiveData()
val photoUri:LiveData=\u photoUri
有趣的startCameraPreview(lifecycleOwner:lifecycleOwner,surfaceProvider:Preview.surfaceProvider){
照相机,开始(
遗嘱执行人,
生命周期所有者,
表面记录器
)
}
趣事(续){
val photoFile=File(
outputDirectoryProvider.getOutputDirectory(),
简化格式(
文件名\u格式,Locale.US
).format(System.currentTimeMillis())+“.jpg”
)
_photoUri.value=takePictureUseCase.execute(
摄像机,
照片文件,
)
}
有趣的导航返回(screenNavigator:screenNavigator){
screenNavigator.navigateBack()
}
伴星{
private const val FILENAME_FORMAT=“yyyy MM dd HH MM ss SSS”
}
}
类默认摄影机(
private val cameraProviderFuture:ListenableFuture,
私有val预览配置:IPreviewConfiguration,
专用val imageCaptureConfiguration:IIImageCaptureConfiguration,
):伊卡梅拉{
private val cameraProvider:ProcessCameraProvider=cameraProviderFuture.get()
私有变量imageCapture:imageCapture=imageCaptureConfiguration.configure()
private val cameraSelector=cameraSelector.DEFAULT\u BACK\u摄像机
超越有趣的开始(
执行人:执行人,
lifeCycleOwner:lifeCycleOwner,
previewSurface:Preview.SurfaceProvider
) {
cameraProviderFuture.addListener(
可运行{
试一试{
装订预览(
生命周期所有者,
previewConfiguration.configure(previewSurface)
)
}捕获(exc:异常){
Timber.e(exc,“用例绑定失败”)
}
},遗嘱执行人
)
}
private fun bindPreview(lifeCycleOwner:lifeCycleOwner,preview:preview
class TakeAfterPictureViewModel(
private val takePictureUseCase: TakePictureUseCase,
private val outputDirectoryProvider: PhotoOutputDirectoryProvider,
private val camera: ICamera,
private val executor: Executor
) : ViewModel() {
private val _photoUri: MutableLiveData<Uri> = MutableLiveData()
val photoUri: LiveData<Uri> = _photoUri
fun startCameraPreview(lifecycleOwner: LifecycleOwner, surfaceProvider: Preview.SurfaceProvider){
camera.start(
executor,
lifecycleOwner,
surfaceProvider
)
}
fun takeAfterPicture(){
val photoFile = File(
outputDirectoryProvider.getOutputDirectory(),
SimpleDateFormat(
FILENAME_FORMAT, Locale.US
).format(System.currentTimeMillis()) + ".jpg"
)
_photoUri.value = takePictureUseCase.execute(
camera,
photoFile,
)
}
fun navigateBack(screenNavigator: ScreenNavigator){
screenNavigator.navigateBack()
}
companion object {
private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
}
}
class DefaultCamera(
private val cameraProviderFuture: ListenableFuture<ProcessCameraProvider>,
private val previewConfiguration: IPreviewConfiguration,
private val imageCaptureConfiguration: IImageCaptureConfiguration,
) : ICamera {
private val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
private var imageCapture: ImageCapture = imageCaptureConfiguration.configure()
private val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
override fun start(
executor: Executor,
lifeCycleOwner: LifecycleOwner,
previewSurface: Preview.SurfaceProvider
) {
cameraProviderFuture.addListener(
Runnable {
try {
bindPreview(
lifeCycleOwner,
previewConfiguration.configure(previewSurface)
)
} catch (exc: Exception) {
Timber.e(exc, "Use case binding failed")
}
}, executor
)
}
private fun bindPreview(lifeCycleOwner: LifecycleOwner, preview: Preview) {
// Unbind use cases before rebinding
cameraProvider.unbindAll()
// Bind use cases to camera
cameraProvider.bindToLifecycle(
lifeCycleOwner,
cameraSelector,
preview,
imageCapture
)
}
override fun takePhoto(
outputOptions: ImageCapture.OutputFileOptions,
executor: Executor,
onImageSavedCallback: ImageCapture.OnImageSavedCallback
) {
val imageCapture = imageCapture ?: return
imageCapture.takePicture(
outputOptions,
executor,
onImageSavedCallback
)
}
override fun stop() {
cameraProvider.unbindAll()
}
}