android - CameraX 错误:减少使用计数的次数多于增加次数
问题描述
我正在使用 CameraX 1.0.0-beta01 从服务中拍照。我正在使用 ImageCapture 和 ImageAnalysis - 即没有预览。
我正在实施LifeCycleOwner
和调用
mLifecycleRegistry = new LifecycleRegistry(this);
mLifecycleRegistry.markState(Lifecycle.State.STARTED);
当我开始服务和mLifecycleRegistry.markState(Lifecycle.State.DESTROYED)
完成拍照时。
我收到用户报告的以下错误,并非特定于任何 android 版本或设备。
Fatal Exception: java.lang.IllegalStateException: Decrementing use count occurs more times than incrementing
at androidx.camera.core.impl.DeferrableSurface.decrementUseCount(DeferrableSurface.java:256)
at androidx.camera.core.impl.DeferrableSurfaces.decrementAll(DeferrableSurfaces.java:173)
at androidx.camera.camera2.internal.CaptureSession.clearConfiguredSurfaces(CaptureSession.java:539)
at androidx.camera.camera2.internal.CaptureSession$StateCallback.onClosed(CaptureSession.java:928)
at androidx.camera.camera2.internal.CaptureSession.forceClose(CaptureSession.java:533)
at androidx.camera.camera2.internal.Camera2CameraImpl$StateCallback.onDisconnected(Camera2CameraImpl.java:1210)
at androidx.camera.camera2.internal.CameraDeviceStateCallbacks$ComboDeviceStateCallback.onDisconnected(CameraDeviceStateCallbacks.java:112)
at androidx.camera.camera2.internal.compat.CameraDeviceCompat$StateCallbackExecutorWrapper$2.run(CameraDeviceCompat.java:121)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.os.HandlerThread.run(HandlerThread.java:61)
我自己无法重现该错误。什么可能导致这种情况?
更新:
我找到了DeferrableSurface.java的来源,它发生在这里:
/**
* Decrements the use count.
*
* <p>If this causes the use count to go to zero and the surface has been closed, this will
* complete the future returned by {@link #getTerminationFuture()}.
*/
public void decrementUseCount() {
// If this gets set, then the surface will terminate
CallbackToFutureAdapter.Completer<Void> terminationCompleter = null;
synchronized (mLock) {
if (mUseCount == 0) {
throw new IllegalStateException("Decrementing use count occurs more times than "
+ "incrementing");
}
mUseCount--;
if (mUseCount == 0 && mClosed) {
terminationCompleter = mTerminationCompleter;
mTerminationCompleter = null;
}
// ...
这是从DeferrableSurfaces.java调用的:
/**
* Decrements the usage counts of every surface in the provided list.
*
* @param surfaceList The list of surfaces whose usage count should be decremented.
*/
public static void decrementAll(@NonNull List<DeferrableSurface> surfaceList) {
for (DeferrableSurface surface : surfaceList) {
surface.decrementUseCount();
}
}
我想当我将当前状态标记为时会调用它DESTROYED
。很想说这看起来像一个错误。想法?
更新 2: 我的代码,精简到相关的内容:
public class MyService extends Service implements LifecycleOwner{
private LifecycleRegistry mLifecycleRegistry;
public static boolean serviceRunning = false;
private boolean isCameraOff = true;
private ImageCapture imageCapture;
private int pendingImages = 0;
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
/* called from activity when we should take a picture.
can be called several times, and we therefore increment an
int, keeping track of how many pictures should be taken. */
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
serviceRunning = true;
// Increment pending pictures
pendingImages++;
// if camera is not in use, setup camera and take picture, otherwise incrementing pendingImages var is enough
if(isCameraOff){
isCameraOff = false;
cameraSetup(); // takePicture called from the end of setup
}
return START_NOT_STICKY;
}
private void cameraSetup(){
// lifecycle for camera
mLifecycleRegistry = new LifecycleRegistry(this);
mLifecycleRegistry.setCurrentState(Lifecycle.State.STARTED);
ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
// Camera provider is now guaranteed to be available
ProcessCameraProvider cameraProvider = (ProcessCameraProvider)cameraProviderFuture.get();
// Dummy Analyzer
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
// empty analyzer, for the time
imageAnalysis.setAnalyzer(executor, ImageProxy::close);
// ImageCapture
imageCapture = new ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
.setTargetResolution(new Size(900,1200))
.build();
// Select front facing camera
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_FRONT)
.build();
// Bind Camera to lifecycle
cameraProvider.bindToLifecycle(this, cameraSelector, imageCapture, imageAnalysis);
// Give camera some time to open, 500 ms should do, before proceeding
Utils.sleepThread(500);
// take picture
takePicture();
} catch (InterruptedException | ExecutionException e) {
// Currently no exceptions thrown. cameraProviderFuture.get() should
// not block since the listener is being called, so no need to
// handle InterruptedException.
}
}, ContextCompat.getMainExecutor(this));
}
private Executor executor = Executors.newSingleThreadExecutor();
private void takePicture(){
// Create new file
File file = new File(Utils.createFilePath(context, getApplication()));
// Create Meta data
ImageCapture.Metadata meta = new ImageCapture.Metadata();
meta.setReversedHorizontal(false); // don't mirror photos
// Collect file options
ImageCapture.OutputFileOptions outputFileOptions =
new ImageCapture.OutputFileOptions.Builder(file)
.setMetadata(meta)
.build();
// Take picture
imageCapture.takePicture(outputFileOptions, executor, new ImageCapture.OnImageSavedCallback(){
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
// got picture
// Decrement the number of pictures we need to take
pendingImages--;
// take another image if pending
if(pendingImages > 0){
takePicture();
}else{
closeSession();
}
}
@Override
public void onError(@NonNull ImageCaptureException exception) {
exception.printStackTrace();
closeSession();
}
});
}
private void closeSession(){
// tell lifecycle and thus camera to close (has to be called from main thread)
// closeSession is called from the camera callback and is not on main thread.
new Handler(context.getMainLooper()).post(() -> {
mLifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED);
});
// mark camera as off
isCameraOff = true;
stopSelf(); // stop service
}
@Override
public void onDestroy() {
super.onDestroy();
serviceRunning = false;
}
// Service Stuff
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
解决方案
推荐阅读
- pytorch - BERT 模型加载不适用于 pytorch 1.3.1-eia 容器
- java - 当它创建的线程死亡时,进程是否会死亡?
- oracle - 为什么即使更新索引附加了语句,删除分区时索引也会进入不可用状态
- node.js - socket-io:发送消息时,如何向根组件/聊天室外显示消息/通知?
- r - 如何将点移近情节?
- c# - 无法访问 IIS Web API
- ios - SwiftUI:独立视图层
- python - 无法安装带有 pipenv 和 big sur 的 jupyter(或 jupyter lab)
- javascript - 从另一个数组中获取相同的值并分配给数组对象
- amazon-web-services - terraform 中的 User_data 无法接收 pem 密钥的变量