В настоящее время я работаю над приложением «умное зеркало» для своего планшета (Android 7.0), которое включает службу, которая постоянно делает снимки, не отображая их с помощью .setRepeatingRequest. Этот сервис сохраняет все изображения в одном месте / image.jpg, так что image.jpg постоянно обновляется (около 3 кадров в секунду). Время от времени приложение вылетает, и я не могу понять, почему.
Это типичный поток процессов:
Приложение запускается -> Основное действие (отображает некоторые данные о погоде и т. Д.) -> Через несколько секунд обработчик запускает второе действие (вызывая startActivity (намерение)) -> это второе действие запускает службу с
startService(new Intent(this, Camera2Service.class));
-> теперь каждую секунду приложение проверяет наличие видимых граней на текущем изображении и, если да, запускаетActivity (намерение); снова через короткую задержку возвращается к основному, и цикл запускает новое.
Это прекрасно работает большую часть времени, то есть много циклов без ошибок. Приложение переключается назад и вперед от отображения основного действия к второму действию «blackscreen-sleepmode» и обратно, как только лицо распознается на одном из изображений. Теперь, иногда после одного цикла, иногда после десяти, кажется, что secondActicity аварийно завершает работу или, по крайней мере, приложение переключается обратно на главную без обычного приветственного сообщения, в то время как в logcat появляется следующая ошибка:
java.lang.IllegalStateException: Session has been closed; further changes are illegal.
at android.hardware.camera2.impl.CameraCaptureSessionImpl.checkNotClosed(CameraCaptureSessionImpl.java:607)
at android.hardware.camera2.impl.CameraCaptureSessionImpl.setRepeatingRequest(CameraCaptureSessionImpl.java:227)
После этого mainActivity ведет обратный отсчет, как обычно, до тех пор, пока не попытается переключиться на второе действие. В тот момент, когда secondActivity пытается снова запустить службу, приложение, наконец, полностью вылетает с:
2019-01-27 03:05:19.166 22434-22434/com.krautkremer.nils.mymirror E/BufferItemConsumer: [ImageReader-640x480f100m2-22434-0] Failed to release buffer: Unknown error -1 (1)
2019-01-27 03:05:19.166 22434-22434/com.krautkremer.nils.mymirror E/BufferItemConsumer: [ImageReader-640x480f100m2-22434-0] Failed to release buffer: Unknown error -1 (1)
2019-01-27 03:05:19.166 22434-22434/com.krautkremer.nils.mymirror E/BufferItemConsumer: [ImageReader-640x480f100m2-22434-0] Failed to release buffer: Unknown error -1 (1)
2019-01-27 03:05:19.176 22434-22434/com.krautkremer.nils.mymirror E/BufferItemConsumer: [ImageReader-640x480f100m2-22434-0] Failed to release buffer: Unknown error -1 (1)
2019-01-27 03:05:19.178 22434-22434/com.krautkremer.nils.mymirror E/CameraCaptureSession: Session 0: Exception while stopping repeating:
android.hardware.camera2.CameraAccessException: CAMERA_DISCONNECTED (2): checkPidStatus:1096: The camera device has been disconnected
at android.hardware.camera2.CameraManager.throwAsPublicException(CameraManager.java:633)
at android.hardware.camera2.impl.ICameraDeviceUserWrapper.cancelRequest(ICameraDeviceUserWrapper.java:95)
at android.hardware.camera2.impl.CameraDeviceImpl.stopRepeating(CameraDeviceImpl.java:926)
at android.hardware.camera2.impl.CameraCaptureSessionImpl.close(CameraCaptureSessionImpl.java:379)
at android.hardware.camera2.impl.CameraCaptureSessionImpl$2.onDisconnected(CameraCaptureSessionImpl.java:515)
at android.hardware.camera2.impl.CameraDeviceImpl$7.run(CameraDeviceImpl.java:228)
at android.os.Handler.handleCallback(Handler.java:761)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:156)
at android.app.ActivityThread.main(ActivityThread.java:6623)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
Caused by: android.os.ServiceSpecificException: checkPidStatus:1096: The camera device has been disconnected
at android.os.Parcel.readException(Parcel.java:1679)
at android.os.Parcel.readException(Parcel.java:1618)
at android.hardware.camera2.ICameraDeviceUser$Stub$Proxy.cancelRequest(ICameraDeviceUser.java:350)
at android.hardware.camera2.impl.ICameraDeviceUserWrapper.cancelRequest(ICameraDeviceUserWrapper.java:93)
at android.hardware.camera2.impl.CameraDeviceImpl.stopRepeating(CameraDeviceImpl.java:926)
at android.hardware.camera2.impl.CameraCaptureSessionImpl.close(CameraCaptureSessionImpl.java:379)
at android.hardware.camera2.impl.CameraCaptureSessionImpl$2.onDisconnected(CameraCaptureSessionImpl.java:515)
at android.hardware.camera2.impl.CameraDeviceImpl$7.run(CameraDeviceImpl.java:228)
at android.os.Handler.handleCallback(Handler.java:761)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:156)
at android.app.ActivityThread.main(ActivityThread.java:6623)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
2019-01-27 03:05:19.183 22434-22434/com.krautkremer.nils.mymirror E/CameraCaptureSession: Session 0: Failed to create capture session; configuration failed
2019-01-27 03:05:19.183 22434-22434/com.krautkremer.nils.mymirror E/logging: CAMERA_DISCONNECTED (2): checkPidStatus:1096: The camera device has been disconnected
2019-01-27 03:05:19.186 26720-26720/? E/FullInputEventModel: onStartInput event aborted: eeg: could not obtain extracted text (class eeg)
2019-01-27 03:05:19.187 431-2732/? E/ANDR-PERF-MPCTL: invalid request, no optimizations performed
2019-01-27 03:05:19.187 22783-22783/? E/QCamera: <MCI><ERROR> mm_channel_fsm_fn_stopped: 918: invalid state (1) for evt (6)
2019-01-27 03:05:19.235 22783-22783/? E/mm-still: virtual OMX_ERRORTYPE QOMXImageCodec::omx_component_set_callbacks(OMX_HANDLETYPE, OMX_CALLBACKTYPE *, OMX_PTR): Bad Parameter
2019-01-27 03:05:19.236 22783-22783/? E/QCamera: <HAL><ERROR> int32_t qcamera::QCameraPerfLock::lock_rel(): 448: failed to release lock
2019-01-27 03:05:19.262 22783-22889/? E/Camera2-Metadata: Mismatched tag type when updating entry enable (-2146959360) of type byte; got type int32 data instead
2019-01-27 03:05:19.262 22783-22889/? E/Camera2-Metadata: Mismatched tag type when updating entry is_main (-2146959359) of type byte; got type int32 data instead
2019-01-27 03:05:19.264 22434-22434/com.krautkremer.nils.mymirror E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.krautkremer.nils.mymirror, PID: 22434
java.lang.IllegalStateException: Session has been closed; further changes are illegal.
at android.hardware.camera2.impl.CameraCaptureSessionImpl.checkNotClosed(CameraCaptureSessionImpl.java:607)
at android.hardware.camera2.impl.CameraCaptureSessionImpl.setRepeatingRequest(CameraCaptureSessionImpl.java:227)
at com.krautkremer.nils.mymirror.Camera2Service$2.onReady(Camera2Service.java:80)
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:761)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:156)
at android.app.ActivityThread.main(ActivityThread.java:6623)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
Так что я считаю, что окончательный сбой происходит, потому что служба и повторяющийся запрос раньше не закрывались должным образом. Мой вопрос заключается в том, почему я иногда получаю эти странные исключения IllegalStateExceptions, во-первых, которые мешают SecondActivity прекращать работу службы.
Я знаю, что есть некоторые вопросы SO, относящиеся к подобной ошибке, но я не нашел ни одного из них, подходящих для этой особой ситуации (repeatableRequest, Service).
Спасибо за вашу помощь, я новичок в Android и Java, и этот camera2api очень сбивает меня с толку. Это соответствующие части моего кода, пожалуйста, спросите, если вам нужно что-то еще:
Класс обслуживания:
public class Camera2Service extends Service
{
protected static final String TAG = "logging";
protected static final int CAMERACHOICE = CameraCharacteristics.LENS_FACING_BACK;
protected CameraDevice cameraDevice;
protected CameraCaptureSession session;
protected ImageReader imageReader;
private Handler mHandler = new Handler();
protected CameraDevice.StateCallback cameraStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
Log.i(TAG, "CameraDevice.StateCallback onOpened");
cameraDevice = camera;
actOnReadyCameraDevice();
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
Log.i(TAG, "CameraDevice.StateCallback onDisconnected");
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
Log.i(TAG, "CameraDevice.StateCallback onError " + error);
}
};
protected CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onReady(CameraCaptureSession session) {
Camera2Service.this.session = session;
try {
session.setRepeatingRequest(createCaptureRequest(), null, null);
} catch (CameraAccessException e) {
Log.e(TAG, e.getMessage());
}
}
@Override
public void onConfigured(CameraCaptureSession session) {
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
}
};
protected ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Log.i(TAG, "onImageAvailable");
Image img = reader.acquireLatestImage();
if (img != null) {
processImage(img);
img.close();
}
}
};
public void readyCamera() {
Log.i(TAG, "so far 1");
CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
Log.i(TAG, "so far 2 ");
try {
String pickedCamera = getCamera(manager);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
manager.openCamera(pickedCamera, cameraStateCallback, null);
imageReader = ImageReader.newInstance(640, 480, ImageFormat.JPEG, 2 /* images buffered */);
imageReader.setOnImageAvailableListener(onImageAvailableListener, null);
Log.i(TAG, "imageReader created");
} catch (CameraAccessException e){
Log.i(TAG, e.getMessage());
}
}
public String getCamera(CameraManager manager){
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
int cOrientation = characteristics.get(CameraCharacteristics.LENS_FACING);
Log.i(TAG, "cameraid: " + cameraId);
if (cOrientation != CAMERACHOICE) {
return cameraId;
}
}
} catch (CameraAccessException e){
e.printStackTrace();
}
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand flags " + flags + " startId " + startId);
Log.i(TAG,"onStart service");
readyCamera();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
Log.i(TAG,"onCreate service");
super.onCreate();
}
public void actOnReadyCameraDevice()
{
try {
cameraDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()), sessionStateCallback, null);
} catch (CameraAccessException e){
Log.e(TAG, e.getMessage());
}
}
@Override
public void onDestroy() {
try {
session.stopRepeating();
session.abortCaptures();
} catch (CameraAccessException e){
Log.e(TAG, e.getMessage());
}
session.close();
}
private void processImage(Image image){
//Process image data
ByteBuffer buffer;
byte[] bytes;
boolean success = false;
File file = new File(Environment.getExternalStorageDirectory() + "/Pictures/image.jpg");
FileOutputStream output = null;
if(image.getFormat() == ImageFormat.JPEG) {
buffer = image.getPlanes()[0].getBuffer();
bytes = new byte[buffer.remaining()]; // makes byte array large enough to hold image
buffer.get(bytes); // copies image from buffer to byte array
try {
output = new FileOutputStream(file);
output.write(bytes); // write the byte array to file
//j++;
success = true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
image.close(); // close this to free up buffer for other images
if (null != output) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
protected CaptureRequest createCaptureRequest() {
try {
CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
builder.addTarget(imageReader.getSurface());
builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
builder.set(CaptureRequest.CONTROL_AE_LOCK, true);
builder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 1);
return builder.build();
} catch (CameraAccessException e) {
Log.e(TAG, e.getMessage());
return null;
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
secondActivity onPause () и onResume ():
@Override
protected void onPause(){
super.onPause();
stopService(new Intent(this, Camera2Service.class));
}
@Override
protected void onResume(){
super.onResume();
startService(new Intent(this, Camera2Service.class));
}
И вот как я вернусь к основному:
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
try {
Intent intent = new Intent(sleepingtime.this, MainActivity.class);
startActivity(intent);
} catch(Exception e){
e.printStackTrace();
Log.i(TAG, "Error calling activity MainActivity " + e);
}
}
}, countdownms);
Еще раз спасибо