我正在創建一個支持棄用和新相機API的應用程序。第一個像魅力一樣工作,但我正在苦於與Camera2 API。在測試階段,我注意到了奇怪的行爲。測試設備是三星Galaxy S5採用Android 6.0.1 當我按下電源/結束鍵,然後返回到應用程序,這是我所得到的(這不會發生每次):Camera2 API和java.lang.IllegalStateException
03-12 16:14:32.704 24117-24117/pl.tripper.tripper E/MainActivity: onPause
03-12 16:14:32.774 24117-24128/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-24117-2] dequeueBuffer: BufferQueue has been abandoned
03-12 16:14:32.784 24117-24145/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-24117-2] queueBuffer: BufferQueue has been abandoned
03-12 16:14:33.044 24117-24128/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-24117-2] cancelBuffer: BufferQueue has been abandoned
03-12 16:14:33.044 24117-24145/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-24117-2] cancelBuffer: BufferQueue has been abandoned
03-12 16:14:33.054 24117-24129/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-24117-2] cancelBuffer: BufferQueue has been abandoned
03-12 16:14:33.054 24117-24128/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-24117-2] cancelBuffer: BufferQueue has been abandoned
03-12 16:14:33.264 24117-24117/pl.tripper.tripper E/CameraNewApi: cameraComponentsReleased
03-12 16:14:33.264 24117-24117/pl.tripper.tripper E/CameraNewApi: StopCameraThread
03-12 16:14:33.264 24117-24117/pl.tripper.tripper E/CameraApiManager: cameraPreviewRemoved
03-12 16:14:33.264 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceDestroyed
03-12 16:14:33.634 24117-24117/pl.tripper.tripper E/MainActivity: onCreate
03-12 16:14:33.634 24117-24117/pl.tripper.tripper E/MainActivity: onResume
03-12 16:14:33.634 24117-24117/pl.tripper.tripper E/CameraNewApi: startCameraThread
03-12 16:14:33.634 24117-24117/pl.tripper.tripper E/CameraApiManager: cameraPreviewCreated
03-12 16:14:33.644 24117-24117/pl.tripper.tripper E/CameraNewApi: initCamera
03-12 16:14:33.674 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceCreated
03-12 16:14:33.674 24117-24117/pl.tripper.tripper E/CameraNewApi: openCamera
03-12 16:14:33.914 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceChanged
03-12 16:14:33.914 24117-25053/pl.tripper.tripper E/CameraNewApi: onOpened
03-12 16:14:33.914 24117-25053/pl.tripper.tripper E/CameraNewApi: createCameraPreview
03-12 16:14:33.934 24117-24117/pl.tripper.tripper E/MainActivity: onPause
03-12 16:14:34.174 24117-24117/pl.tripper.tripper E/CameraNewApi: cameraComponentsReleased
03-12 16:14:34.174 24117-25053/pl.tripper.tripper E/CameraNewApi: onConfigured
03-12 16:14:34.174 24117-24117/pl.tripper.tripper E/CameraNewApi: StopCameraThread
03-12 16:14:34.174 24117-24117/pl.tripper.tripper E/CameraApiManager: cameraPreviewRemoved
03-12 16:14:34.184 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceDestroyed
03-12 16:14:34.914 24117-24117/pl.tripper.tripper E/MainActivity: onResume
03-12 16:14:34.914 24117-24117/pl.tripper.tripper E/CameraNewApi: startCameraThread
03-12 16:14:34.924 24117-24117/pl.tripper.tripper E/CameraApiManager: cameraPreviewCreated
03-12 16:14:34.924 24117-24117/pl.tripper.tripper E/CameraNewApi: initCamera
03-12 16:14:34.964 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceCreated
03-12 16:14:34.964 24117-24117/pl.tripper.tripper E/CameraNewApi: openCamera
03-12 16:14:35.294 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceChanged
03-12 16:14:35.294 24117-25121/pl.tripper.tripper E/CameraNewApi: onOpened
03-12 16:14:35.294 24117-25121/pl.tripper.tripper E/CameraNewApi: createCameraPreview
03-12 16:14:35.354 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceChanged
03-12 16:14:35.374 24117-24117/pl.tripper.tripper E/MainActivity: onPause
03-12 16:14:35.384 24117-25121/pl.tripper.tripper E/CameraNewApi: onConfigured
03-12 16:14:35.594 24117-24117/pl.tripper.tripper E/CameraNewApi: cameraComponentsReleased
03-12 16:14:35.594 24117-25121/pl.tripper.tripper E/CameraNewApi: Session was closed or camera device has been closed.
java.lang.IllegalStateException: CameraDevice was already closed
at android.hardware.camera2.impl.CameraDeviceImpl.checkIfCameraClosedOrInError(CameraDeviceImpl.java:1997)
at android.hardware.camera2.impl.CameraDeviceImpl.submitCaptureRequest(CameraDeviceImpl.java:844)
at android.hardware.camera2.impl.CameraDeviceImpl.setRepeatingRequest(CameraDeviceImpl.java:899)
at android.hardware.camera2.impl.CameraCaptureSessionImpl.setRepeatingRequest(CameraCaptureSessionImpl.java:236)
at pl.tripper.tripper.camera.CameraNewApi$2.onConfigured(CameraNewApi.java:107)
at java.lang.reflect.Method.invoke(Native Method)
at android.hardware.camera2.dispatch.InvokeDispatcher.dispatch(InvokeDispatcher.java:39)
at android.hardware.camera2.dispatch.HandlerDispatcher$1.run(HandlerDispatcher.java:65)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.os.HandlerThread.run(HandlerThread.java:61)
03-12 16:14:35.594 24117-24117/pl.tripper.tripper E/CameraNewApi: StopCameraThread
03-12 16:14:35.594 24117-25121/pl.tripper.tripper E/CameraNewApi: cameraComponentsReleased
03-12 16:14:35.594 24117-24117/pl.tripper.tripper E/CameraApiManager: cameraPreviewRemoved
03-12 16:14:35.604 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceDestroyed
03-12 16:14:35.644 24117-24117/pl.tripper.tripper E/MainActivity: onCreate
03-12 16:14:35.654 24117-24117/pl.tripper.tripper E/MainActivity: onResume
03-12 16:14:35.654 24117-24117/pl.tripper.tripper E/CameraNewApi: startCameraThread
03-12 16:14:35.654 24117-24117/pl.tripper.tripper E/CameraApiManager: cameraPreviewCreated
03-12 16:14:35.654 24117-24117/pl.tripper.tripper E/CameraNewApi: initCamera
03-12 16:14:35.694 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceCreated
03-12 16:14:35.694 24117-24117/pl.tripper.tripper E/CameraNewApi: openCamera
03-12 16:14:35.934 24117-24117/pl.tripper.tripper E/CameraNewApi: onSurfaceChanged
03-12 16:14:35.934 24117-25184/pl.tripper.tripper E/CameraNewApi: onOpened
03-12 16:14:35.934 24117-25184/pl.tripper.tripper E/CameraNewApi: createCameraPreview
03-12 16:14:35.944 24117-24117/pl.tripper.tripper E/ViewRootImpl: sendUserActionEvent() mView == null
03-12 16:14:35.944 24117-24117/pl.tripper.tripper E/ViewRootImpl: sendUserActionEvent() mView == null
03-12 16:14:35.994 24117-25184/pl.tripper.tripper E/CameraNewApi: onConfigured
增加了一些錯誤日誌當方法被調用時。我知道cameraDevice在會話仍然運行時爲空,但我不知道如何解決它。相機在java.lang.IllegalStateException
錯誤後仍繼續工作。第二個問題是BufferQueueProducer
錯誤,但我無法弄清楚這是從哪裏來的。
03-12 15:47:40.244 30720-30731/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-30720-1] dequeueBuffer: BufferQueue has been abandoned 03-12 15:47:40.244 30720-30751/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-30720-1] queueBuffer: BufferQueue has been abandoned 03-12 15:47:40.524 30720-30731/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-30720-1] cancelBuffer: BufferQueue has been abandoned 03-12 15:47:40.524 30720-30751/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-30720-1] cancelBuffer: BufferQueue has been abandoned 03-12 15:47:40.524 30720-30732/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-30720-1] cancelBuffer: BufferQueue has been abandoned 03-12 15:47:40.524 30720-30731/pl.tripper.tripper E/BufferQueueProducer: [SurfaceTexture-1-30720-1] cancelBuffer: BufferQueue has been abandoned
這裏是我的代碼:
MainActivity.class
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
Log.e(TAG, "onCreate");
isImmersiveAvailable();
cameraApiManager = new CameraApiManager(this, this);
}
@Override
protected void onResume() {
super.onResume();
Log.e(TAG, "onResume");
cameraApiManager.createCamera();
}
@Override
protected void onPause() {
super.onPause();
Log.e(TAG, "onPause");
cameraApiManager.releaseCameraAndPreview();
}
CameraApiManager.class
public class CameraApiManager implements CameraUtility.cameraOpenedListener {
private static final String TAG = "CameraApiManager";
private final WeakReference<MainActivity> mainActivity;
private Context context;
private CameraSourceApi cameraSourceApi;
private CameraPreview cameraPreview;
public CameraApiManager(Context context, MainActivity mainActivity){
this.mainActivity= new WeakReference<>(mainActivity);
cameraSourceApi = new CameraSourceApi<>(new CameraNewApi(context));
this.context = context;
}
private boolean cameraProgressBarEnable(){
return context.getResources().getBoolean(R.bool.camera_progress_bar_enable);
}
private void setCameraProgressBarVisibility(final int visibility){
final MainActivity mainActivity = this.mainActivity.get();
if(mainActivity!= null){
// UI/Main Thread
if(Looper.myLooper() == Looper.getMainLooper()){
ProgressBar cameraProgressBar = (ProgressBar) mainActivity.findViewById(R.id.camera_progress_bar);
cameraProgressBar.setVisibility(visibility);
} else {
mainActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
ProgressBar cameraProgressBar = (ProgressBar) mainActivity.findViewById(R.id.camera_progress_bar);
cameraProgressBar.setVisibility(visibility);
}
});
}
}
}
private void showCameraOpenErrorToast(){
Toast.makeText(context, context.getResources().getString(R.string.camera_open_error_toast), Toast.LENGTH_LONG).show();
}
private boolean cameraPermissionGranted() {
return ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
}
public void createCamera(){
if(cameraPermissionGranted()){
if(cameraProgressBarEnable()){
setCameraProgressBarVisibility(View.VISIBLE);
}
cameraSourceApi.createCamera(this);
}
}
public void releaseCameraAndPreview(){
if(cameraPermissionGranted()){
cameraSourceApi.releaseCamera();
removeCameraPreview();
}
}
@Override
public void onCameraOpened(boolean succeeded, boolean addPreview, boolean progressBar) {
if(addPreview) {
if (cameraPreview == null) {
Log.e(TAG, "cameraPreviewCreated");
cameraPreview = new CameraPreview(context, cameraSourceApi);
addCameraPreview();
}
}
if(!progressBar){
if(cameraProgressBarEnable()){
setCameraProgressBarVisibility(View.GONE);
}
}
if(!succeeded){
showCameraOpenErrorToast();
}
}
private void addCameraPreview(){
MainActivity mainActivity = this.mainActivity.get();
if(mainActivity != null && cameraPreview != null){
FrameLayout preview = (FrameLayout) mainActivity.findViewById(R.id.camera_preview);
preview.addView(cameraPreview);
}
}
private void removeCameraPreview(){
MainActivity mainActivity = this.mainActivity.get();
if(mainActivity!= null && cameraPreview != null){
Log.e(TAG, "cameraPreviewRemoved");
FrameLayout preview = (FrameLayout) mainActivity.findViewById(R.id.camera_preview);
preview.removeView(cameraPreview);
cameraPreview = null;
}
}
class CameraSourceApi<T extends CameraUtility> implements CameraUtility{
private T camera;
CameraSourceApi(T camera){
this.camera = camera;
}
@Override
public void createCamera(CameraUtility.cameraOpenedListener cameraOpenedListener) {
camera.createCamera(cameraOpenedListener);
}
@Override
public void releaseCamera() {
camera.releaseCamera();
}
@Override
public void onSurfaceCreated(SurfaceHolder surfaceHolder) {
camera.onSurfaceCreated(surfaceHolder);
}
@Override
public void onSurfaceChanged(SurfaceHolder surfaceHolder, int width, int height) {
camera.onSurfaceChanged(surfaceHolder, width, height);
}
@Override
public void onSurfaceDestroyed(SurfaceHolder surfaceHolder) {
camera.onSurfaceDestroyed(surfaceHolder);
}
}
}
CameraNewApi.class
@TargetApi(21)
class CameraNewApi implements CameraUtility {
private static final String TAG = "CameraNewApi";
private Semaphore cameraOpenCloseLock = new Semaphore(1);
private CameraUtility.cameraOpenedListener cameraOpenedListener;
private Context context;
private Handler backgroundHandler;
private HandlerThread backgroundThread;
private SurfaceHolder surfaceHolder;
private String backFacingCameraId;
private CaptureRequest.Builder captureRequestBuilder;
private CameraDevice cameraDevice;
private CameraCaptureSession cameraCaptureSessions;
CameraNewApi(Context context){
this.context = context;
}
private final CameraDevice.StateCallback cameraDeviceStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
Log.e(TAG, "onOpened");
cameraOpenCloseLock.release();
cameraDevice = camera;
if(surfaceHolder != null){
createCameraPreview();
} else {
releaseCameraComponents();
}
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
Log.d(TAG, "deviceCallback.onDisconnected() start");
Log.e(TAG, "onDisconnected");
if(cameraOpenedListener != null) {
cameraOpenedListener.onCameraOpened(false, false, false);
}
cameraOpenCloseLock.release();
camera.close();
cameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
Log.e(TAG, "onError");
Log.d(TAG, "deviceCallback.onError() start");
if(cameraOpenedListener != null) {
cameraOpenedListener.onCameraOpened(false, false, false);
}
cameraOpenCloseLock.release();
camera.close();
cameraDevice = null;
}
};
private final CameraCaptureSession.StateCallback captureSessionStateCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
Log.e(TAG, "onConfigured");
if(cameraDevice != null){
cameraCaptureSessions = session;
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
try {
if(cameraOpenedListener != null) {
cameraOpenedListener.onCameraOpened(true, false, false);
}
session.setRepeatingRequest(captureRequestBuilder.build(), null, backgroundHandler);
} catch (CameraAccessException e) {
Log.e(TAG, "Camera has been disconnected", e);
} catch (IllegalStateException e){
Log.e(TAG, "Session was closed or camera device has been closed. ", e);
releaseCameraComponents();
}
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Log.d(TAG, "Capture session configure failed: " + session);
Log.e(TAG, "onConfigureFailed");
}
};
@Override
public void createCamera(CameraUtility.cameraOpenedListener cameraOpenedListener) {
this.cameraOpenedListener = cameraOpenedListener;
startBackgroundThread();
if(cameraOpenedListener != null){
cameraOpenedListener.onCameraOpened(true, true, true);
}
initCamera();
}
private void releaseCameraComponents(){
try{
cameraOpenCloseLock.acquire();
if(cameraCaptureSessions != null){
cameraCaptureSessions.close();
cameraCaptureSessions = null;
}
if(cameraDevice != null){
cameraDevice.close();
cameraDevice = null;
}
if(surfaceHolder != null){
surfaceHolder = null;
}
if(cameraOpenedListener != null){
cameraOpenedListener = null;
}
Log.e(TAG, "cameraComponentsReleased");
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
cameraOpenCloseLock.release();
}
}
@Override
public void releaseCamera() {
releaseCameraComponents();
stopBackgroundThread();
}
@Override
public void onSurfaceCreated(SurfaceHolder surfaceHolder) {
Log.e(TAG, "onSurfaceCreated");
this.surfaceHolder = surfaceHolder;
openCamera();
}
@Override
public void onSurfaceChanged(SurfaceHolder surfaceHolder, int width, int height) {
Log.e(TAG, "onSurfaceChanged");
setSurfaceSize(width, height);
}
@Override
public void onSurfaceDestroyed(SurfaceHolder surfaceHolder) {
Log.e(TAG, "onSurfaceDestroyed");
}
private void startBackgroundThread() {
Log.e(TAG, "startCameraThread");
backgroundThread = new HandlerThread("CameraBackground");
backgroundThread.start();
backgroundHandler = new Handler(backgroundThread.getLooper());
}
private void stopBackgroundThread() {
Log.e(TAG, "StopCameraThread");
backgroundThread.quitSafely();
try {
backgroundThread.join();
backgroundThread = null;
backgroundHandler = null;
} catch (InterruptedException e) {
Log.e(TAG, "Error message: ", e);
}
}
private void initCamera(){
Log.e(TAG, "initCamera");
CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
try{
for (String cameraId : cameraManager.getCameraIdList()) {
CameraCharacteristics characteristics
= cameraManager.getCameraCharacteristics(cameraId);
// Use back camera
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) {
backFacingCameraId = cameraId;
break;
}
}
if(backFacingCameraId == null){
Log.d(TAG, "Could not detect a camera");
}
} catch (CameraAccessException e) {
Log.e(TAG, "Could not get camera list", e);
}
}
private void openCamera(){
Log.e(TAG, "openCamera");
CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
try{
if(backFacingCameraId != null && cameraDevice == null){
try{
if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
cameraManager.openCamera(backFacingCameraId, cameraDeviceStateCallback, backgroundHandler);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}
} catch(SecurityException e){
Log.e(TAG, "Camera permission is not granted", e);
} catch(CameraAccessException e){
Log.e(TAG, "Could not open camera", e);
}
}
private void createCameraPreview(){
Log.e(TAG, "createCameraPreview");
Surface surface = surfaceHolder.getSurface();
List<Surface> surfaceList = Collections.singletonList(surface);
try {
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(surfaceList, captureSessionStateCallback, null);
} catch (CameraAccessException e){
Log.e(TAG, "Could not create capture session for camera: " + cameraDevice.getId(), e);
} catch (IllegalStateException e){
Log.e(TAG, "Camera has been closed", e);
}
}
CameraUtility.interface
interface CameraUtility {
void createCamera(CameraUtility.cameraOpenedListener cameraOpenedListener);
void releaseCamera();
void onSurfaceCreated(SurfaceHolder surfaceHolder);
void onSurfaceChanged(SurfaceHolder surfaceHolder, int width, int height);
void onSurfaceDestroyed(SurfaceHolder surfaceHolder);
interface cameraOpenedListener{
void onCameraOpened(boolean succeeded, boolean addPreview, boolean progressBar);
}
}
UPDATE
這就是爲什麼它不會每次發生。在調用onPause之後立即發生錯誤,會話開始重複請求以維護預覽(onConfigured)。然後cameraComponentsReleased觸發器完成所有清理,包括當前的CameraDevice對象。仍然沒有線索如何管理這種情況。
03-13 12:12:24.375 17555-17555/pl.tripper.tripper E/MainActivity: onPause
03-13 12:12:24.395 17555-20454/pl.tripper.tripper E/CameraNewApi: onConfigured
03-13 12:12:24.625 17555-17555/pl.tripper.tripper E/CameraNewApi: cameraComponentsReleased
03-13 12:12:24.625 17555-17555/pl.tripper.tripper E/CameraNewApi: StopCameraThread
03-13 12:12:24.625 17555-20454/pl.tripper.tripper E/CameraNewApi: Session was closed or camera device has been closed.
java.lang.IllegalStateException: CameraDevice was already closed
at android.hardware.camera2.impl.CameraDeviceImpl.checkIfCameraClosedOrInError(CameraDeviceImpl.java:1997)
at android.hardware.camera2.impl.CameraDeviceImpl.submitCaptureRequest(CameraDeviceImpl.java:844)
at android.hardware.camera2.impl.CameraDeviceImpl.setRepeatingRequest(CameraDeviceImpl.java:899)
at android.hardware.camera2.impl.CameraCaptureSessionImpl.setRepeatingRequest(CameraCaptureSessionImpl.java:236)
at pl.tripper.tripper.camera.CameraNewApi$2.onConfigured(CameraNewApi.java:114)
at java.lang.reflect.Method.invoke(Native Method)
at android.hardware.camera2.dispatch.InvokeDispatcher.dispatch(InvokeDispatcher.java:39)
at android.hardware.camera2.dispatch.HandlerDispatcher$1.run(HandlerDispatcher.java:65)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.os.HandlerThread.run(HandlerThread.java:61)
03-13 12:12:24.625 17555-20454/pl.tripper.tripper E/CameraNewApi: Camera onClosed
03-13 12:12:24.625 17555-17555/pl.tripper.tripper E/CameraApiManager: cameraPreviewRemoved
增加了一些新的信息質疑 – sheddar
@You金 - 我認爲你是對的。使用camera2Basic示例有幾種可能的競爭條件,但onConfigured回調實際上是打開序列中的最後一步,所以將它包含在任何同步計劃中都是有意義的。 – Mick