Tôi chỉ chuyển mã của tôi asynctask
-rxjava2
và tôi nhận được một cách ngẫu nhiên ngoại lệ này trên mối quan hệ của tôi:Rxjava 2 ngoại lệ với camera
Máy ảnh đang được sử dụng sau khi Camera.release() được gọi trong thiên hà s6 Cạnh
Sau đây là số- tôi
Lớp Máy ảnh:
public class Cameras {
private static final String TAG = Cameras.class.getSimpleName();
private static final String SP_CAMERA_ID = "camera_id";
private static final int NO_NEXT_TASK = 0;
private static final int NEXT_TASK_RELEASE_COMPLETE = 1;
private static final int NEXT_TASK_SWITCH_COMPLETE = 2;
private static final int NEXT_TASK_START_PREVIEW = 3;
private Camera camera;
private int currentCameraId = -1;
private Camera.PreviewCallback previewCallback;
private byte[] buffer1, buffer2, buffer3;
private SurfaceTexture surfaceTexture;
private Listener listener;
public interface Listener {
void onCameraOpened(Camera.Size size, int angle);
}
private boolean cameraReleased = false;
public Cameras(Camera.PreviewCallback previewCallback, Listener listener) {
this.listener = listener;
this.previewCallback = previewCallback;
this.currentCameraId = Spin.INSTANCE.getSp().getInt(SP_CAMERA_ID, -1);
getCameraList();
}
private void getCameraList() {
int numberOfCameras = Camera.getNumberOfCameras();
Camera.CameraInfo camInfo = new Camera.CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
Camera.getCameraInfo(i, camInfo);
cams.add(camInfo.facing);
}
if (Camera.CameraInfo.CAMERA_FACING_BACK != currentCameraId
&& Camera.CameraInfo.CAMERA_FACING_FRONT != currentCameraId) {
currentCameraId = cams.get(cams.size() == 2 ? 1 : 0);
}
}
public boolean isSwitchCamAvailable() {
return Camera.getNumberOfCameras() > 1;
}
public void open(SurfaceTexture surfaceTexture) {
this.surfaceTexture = surfaceTexture;
init(NEXT_TASK_START_PREVIEW);
}
private void init(final int nextTask) {
if (cams.isEmpty()) {
Toast.makeText(Spin.getContext(), "Device have no camera", Toast.LENGTH_SHORT).show();
return;
}
cameraReleased = false;
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
Observable.defer(new Callable<ObservableSource<?>>() {
@Override
public ObservableSource<?> call() throws Exception {
synchronized (this) {
try {
camera = Camera.open(currentCameraId);
} catch (RuntimeException e) {
e.printStackTrace();
}
}
return Completable.complete().toObservable();
}
}).doOnComplete(() -> {
initComplete(nextTask);
Log.d("Complete", "Complete");
})
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread()).subscribe();
} else {
try {
synchronized (this) {
this.camera = Camera.open(currentCameraId);
}
initComplete(nextTask);
} catch (RuntimeException ignored) {
}
}
}
private void initComplete(int nextTask) {
if (camera == null) {
return;
}
//noinspection SynchronizeOnNonFinalField
synchronized (camera) {
try {
Camera.Parameters params = camera.getParameters();
Camera.Size size = getClosestFrameSize(params, 640);
params.setPreviewSize(size.width, size.height);
camera.setParameters(params);
camera.setPreviewCallbackWithBuffer(previewCallback);
int bufferSize = size.width * size.height
* ImageFormat.getBitsPerPixel(ImageFormat.NV21)/8;
buffer1 = new byte[bufferSize];
buffer2 = new byte[bufferSize];
buffer3 = new byte[bufferSize];
camera.addCallbackBuffer(buffer1);
camera.addCallbackBuffer(buffer2);
camera.addCallbackBuffer(buffer3);
camera.setPreviewTexture(surfaceTexture);
int angle = rotateStream();
camera.setDisplayOrientation(angle);
if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT && angle > 0)
angle = 360 - angle;
listener.onCameraOpened(size, angle);
routNextTask(nextTask);
} catch (IOException | RuntimeException e) {
e.printStackTrace();
}
}
}
private Camera.Size getClosestFrameSize(Camera.Parameters params, int width) {
Camera.Size result = null;
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
Camera.Size currentSize = null;
int closestDistance = 0;
int currentDistance = 0;
for (int i = 0; i < sizes.size(); ++i) {
if (null == result) {
result = sizes.get(i);
closestDistance = Math.abs(result.width - width);
continue;
}
currentSize = sizes.get(i);
currentDistance = Math.abs(currentSize.width - width);
if (currentDistance < closestDistance) {
closestDistance = currentDistance;
result = currentSize;
if (closestDistance == 0) break;
}
}
return result;
}
public void stopPreview() {
stopPreview(NO_NEXT_TASK);
}
private String nextTaskStr(final int nextTask) {
String nextTaskStr = null;
switch (nextTask) {
case NO_NEXT_TASK:
nextTaskStr = "NO_NEXT_TASK";
break;
case NEXT_TASK_RELEASE_COMPLETE:
nextTaskStr = "NEXT_TASK_RELEASE_COMPLETE";
break;
case NEXT_TASK_SWITCH_COMPLETE:
nextTaskStr = "NEXT_TASK_SWITCH_COMPLETE";
break;
case NEXT_TASK_START_PREVIEW:
nextTaskStr = "NEXT_TASK_START_PREVIEW";
break;
}
return nextTaskStr;
}
private void stopPreview(final int nextTask) {
if (null == camera) return;
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
Observable.defer(new Callable<ObservableSource<?>>() {
@Override
public ObservableSource<?> call() throws Exception {
synchronized (this) {
if ((null != camera) && (!cameraReleased)) {
if (LogDog.isEnabled) ;
camera.stopPreview();
}
}
return Completable.complete().toObservable();
}
}).doOnComplete(() -> {
routNextTask(nextTask);
Log.d("Complete", "Complete");
})
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread()).subscribe();
} else {
synchronized (this) {
if ((null != camera) && (!cameraReleased)) {
camera.stopPreview();
}
}
routNextTask(nextTask);
}
}
private void routNextTask(int nextTask) {
if (NO_NEXT_TASK == nextTask) return;
if (NEXT_TASK_SWITCH_COMPLETE == nextTask) {
switchCamComplete();
} else if (NEXT_TASK_RELEASE_COMPLETE == nextTask) {
releaseComplete();
} else if (NEXT_TASK_START_PREVIEW == nextTask) {
startPreview(null);
}
}
public void startPreview(Camera.PreviewCallback cpc) {
if (null == camera) return;
synchronized (this) {
camera.startPreview();
switchCamOnAir = false;
}
}
private void releaseCamera() {
synchronized (this) {
if (null == camera) return;
camera.setPreviewCallback(null);
camera.release();
camera = null;
cameraReleased = true;
}
}
public void release() {
synchronized (this) {
if (null == camera) return;
stopPreview(NEXT_TASK_RELEASE_COMPLETE);
}
}
private void releaseComplete() {
synchronized (this) {
if (camera != null) {
camera.release();
cameraReleased = true;
camera = null;
}
}
buffer1 = null;
buffer2 = null;
buffer3 = null;
}
private boolean switchCamOnAir = false;
public void switchCam() {
if (!isSwitchCamAvailable()) return;
if (null == camera) return;
if (switchCamOnAir) return;
this.switchCamOnAir = true;
stopPreview(NEXT_TASK_SWITCH_COMPLETE);
}
private void switchCamComplete() {
releaseCamera();
if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
} else {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
}
Spin.INSTANCE.getSp().edit().putInt(SP_CAMERA_ID, currentCameraId).apply();
init(NEXT_TASK_START_PREVIEW);
}
public int rotateStream() {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(currentCameraId, info);
WindowManager wm = (WindowManager) Spin.getContext()
.getSystemService(Context.WINDOW_SERVICE);
int rotation = wm.getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
@SuppressWarnings("unused")
public int getDeviceDefaultOrientation() {
WindowManager windowManager = (WindowManager) Spin.getContext()
.getSystemService(Context.WINDOW_SERVICE);
Configuration config = Spin.getContext().getResources().getConfiguration();
int rotation = windowManager.getDefaultDisplay().getRotation();
if (((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) &&
config.orientation == Configuration.ORIENTATION_LANDSCAPE)
|| ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) &&
config.orientation == Configuration.ORIENTATION_PORTRAIT)) {
return Configuration.ORIENTATION_LANDSCAPE;
} else {
return Configuration.ORIENTATION_PORTRAIT;
}
}
}
cameras.java:
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
Observable.defer(new Callable<ObservableSource<?>>() {
@Override
public ObservableSource<?> call() throws Exception {
if (LogDog.isEnabled) LogDog.e("Debug::"+TAG + "::stopPreview()::AsyncTask::doInBackground()", " (camera != null) =" + (camera != null));
synchronized (this) {
if ((null != camera) && (!cameraReleased)) {
if (LogDog.isEnabled) LogDog.e("Debug::" + TAG + "::stopPreview()::AsyncTask::doInBackground()", " XXX CALL camera.stopPreview()");
camera.stopPreview();
}
}
return Completable.complete().toObservable();
}
}).doOnComplete(() -> {
routNextTask(nextTask);
Log.d("Complete", "Complete");
})
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread()).subscribe();
Không chắc những gì tôi đang làm sai. Bất kỳ ý tưởng mà tôi có thể phát hành máy ảnh hoặc phân bổ nó, vì vậy nó hoạt động mà không có bất kỳ vấn đề? ngoại lệ như sau:
EXCEPTION Fatal: chính io.reactivex.exceptions.OnErrorNotImplementedException: Máy ảnh được được sử dụng sau khi Camera.release() được gọi tại io.reactivex.internal.functions.Functions $ OnErrorMissingConsumer.accept (Functions.java:704) tại io.reactivex.internal.functions.Functions $ OnErrorMissingConsumer.accept (Functions.java:701) tại io.reactivex.internal.observers.LambdaObserver.onError (LambdaObserver .java: 74) tại io.reactivex.internal.operators.observable.ObservableObserveOn $ ObserveOnObserver.checkTerminated (ObservableObserveOn.java:276) tại io.reactivex.internal.operators.observable.ObservableObserveOn $ ObserveOnObserver.drainNormal (ObservableObserveOn.java:172) tại io.reactivex.internal.operators.observable.ObservableObserveOn $ ObserveOnObserver.run (ObservableObserveOn.java:252) tại io.reactivex.android.schedulers.HandlerScheduler $ ScheduledRunnable.run (HandlerScheduler.java:109) tại android.os.Handler.handleCallback (Handler.java:751) tại android.os.Handler.dispatchMessage (Handler.java:95) tại android.os.Looper.loop (Looper.java:154) tại android.app.ActivityThread.main (ActivityThread.java:6119) tại java.lang.reflect.Method.invoke (Native Method) tại com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:886) tại com.android.internal.os.ZygoteInit.main (ZygoteInit.java:776) Gây ra bởi: java.lang.RuntimeException: Máy ảnh đang được sử dụng sau Camera.release() được gọi là tại android.hardware.Camera._stopPreview (Phương thức gốc) tại android.hardware.Camera.stopPreview (Camera.java:730) tại com.media.video.Cameras $ 2.call (Cameras.java:413) tại com.media.video.Cameras $ 2.call (Cameras.java:406) tại io.reactivex.internal.operators.observable .ObservableDefer.subscribeActual (ObservableDefer.java: 32) tại io.reactivex.Observable.subscribe (Observable.java:10842) tại io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual (ObservableDoOnEach.java:42) tại io.reactivex.Observable .subscribe (Observable.java:10842) tại io.reactivex.internal.operators.observable.ObservableSubscribeOn $ SubscribeTask.run (ObservableSubscribeOn.java:96) tại io.reactivex.internal.schedulers.ScheduledDirectTask.call (ScheduledDirectTask .java: 38) tại io.reactivex.internal.schedulers.ScheduledDirectTask.call (ScheduledDirectTask.java:26).210 tại java.util.concurrent.FutureTask.run (FutureTask.java:237) tại java.util.concurrent.ScheduledThreadPoolExecutor $ ScheduledFutureTask.run (ScheduledThreadPoolExecutor.java:272) tại java.util.concurrent.ThreadPoolExecutor. runWorker (ThreadPoolExecutor.java:1133) tại java.util.concurrent.ThreadPoolExecutor $ Worker.run (ThreadPoolExecutor.java:607) tại java.lang.Thread.run (Thread.java:761)
Vui lòng thêm một số nhật ký gỡ lỗi khi #releaseComplete()/#startPreview()/#stopPreview()/init() đang được gọi. Sau đó, kích hoạt một ngoại lệ và đăng các dấu vết. –
ngẫu nhiên của nó. đã cố gắng để tái tạo vụ tai nạn này nhưng rất khó để repro, xảy ra ngẫu nhiên. Tôi cũng có một vài bản ghi gỡ lỗi trong mã của tôi, nhưng đã không đăng nó ở đây vì nó sẽ làm cho tập tin lớn hơn và thường mọi người có tâm lý TLDR vì vậy có lẽ wounldt nhìn vào nó. –
Bạn có ít nhất một stacktrace? –