pull/696/head
Mattia Iavarone 6 years ago
parent 959516222b
commit c7028fde9b
  1. 1
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/engine/CameraIntegrationTest.java
  2. 14
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java
  3. 16
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/orchestrator/CameraOrchestrator.java
  4. 8
      cameraview/src/main/java/com/otaliastudios/cameraview/internal/utils/WorkerHandler.java

@ -563,6 +563,7 @@ public abstract class CameraIntegrationTest<E extends CameraEngine> extends Base
@Test @Test
@Retry(emulatorOnly = true) @Retry(emulatorOnly = true)
@SdkExclude(maxSdkVersion = 22, emulatorOnly = true)
public void testSetPreviewFrameRate() { public void testSetPreviewFrameRate() {
CameraOptions options = openSync(true); CameraOptions options = openSync(true);
camera.setPreviewFrameRate(30); camera.setPreviewFrameRate(30);

@ -216,7 +216,7 @@ public abstract class CameraEngine implements
mCrashHandler = new Handler(Looper.getMainLooper()); mCrashHandler = new Handler(Looper.getMainLooper());
mFrameManager = instantiateFrameManager(); mFrameManager = instantiateFrameManager();
mAngles = new Angles(); mAngles = new Angles();
recreateHandler(); recreateHandler(false);
} }
public void setPreview(@NonNull CameraPreview cameraPreview) { public void setPreview(@NonNull CameraPreview cameraPreview) {
@ -276,7 +276,7 @@ public abstract class CameraEngine implements
// (at least in Camera1, e.g. onError). // (at least in Camera1, e.g. onError).
if (fromExceptionHandler) { if (fromExceptionHandler) {
LOG.e("EXCEPTION:", "Handler thread is gone. Replacing."); LOG.e("EXCEPTION:", "Handler thread is gone. Replacing.");
recreateHandler(); recreateHandler(false);
} }
// 2. Depending on the exception, we must destroy(false|true) to release resources, and // 2. Depending on the exception, we must destroy(false|true) to release resources, and
@ -308,7 +308,13 @@ public abstract class CameraEngine implements
}); });
} }
private void recreateHandler() { /**
* Recreates the handler, to ensure we use a fresh one from now on.
* If we suspect that handler is currently stuck, the orchestrator should be reset
* because it hosts a chain of tasks and the last one will never complete.
* @param resetOrchestrator true to reset
*/
private void recreateHandler(boolean resetOrchestrator) {
if (mHandler != null) mHandler.destroy(); if (mHandler != null) mHandler.destroy();
mHandler = WorkerHandler.get("CameraViewEngine"); mHandler = WorkerHandler.get("CameraViewEngine");
mHandler.getThread().setUncaughtExceptionHandler(new CrashExceptionHandler()); mHandler.getThread().setUncaughtExceptionHandler(new CrashExceptionHandler());
@ -370,7 +376,7 @@ public abstract class CameraEngine implements
LOG.e("DESTROY: Could not destroy synchronously after 6 seconds.", LOG.e("DESTROY: Could not destroy synchronously after 6 seconds.",
"Current thread:", Thread.currentThread(), "Current thread:", Thread.currentThread(),
"Handler thread:", mHandler.getThread()); "Handler thread:", mHandler.getThread());
recreateHandler(); recreateHandler(true);
LOG.e("DESTROY: Could not destroy synchronously after 6 seconds.", LOG.e("DESTROY: Could not destroy synchronously after 6 seconds.",
"Trying again on thread:", mHandler.getThread()); "Trying again on thread:", mHandler.getThread());
destroy(unrecoverably); destroy(unrecoverably);

@ -11,7 +11,9 @@ import com.otaliastudios.cameraview.CameraLogger;
import com.otaliastudios.cameraview.internal.utils.WorkerHandler; import com.otaliastudios.cameraview.internal.utils.WorkerHandler;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
@ -161,6 +163,20 @@ public class CameraOrchestrator {
} }
} }
public void reset() {
synchronized (mLock) {
List<String> all = new ArrayList<>();
//noinspection CollectionAddAllCanBeReplacedWithConstructor
all.addAll(mDelayedJobs.keySet());
for (Token token : mJobs) {
all.add(token.name);
}
for (String job : all) {
remove(job);
}
}
}
private void ensureToken() { private void ensureToken() {
synchronized (mLock) { synchronized (mLock) {
if (mJobs.isEmpty()) { if (mJobs.isEmpty()) {

@ -96,7 +96,13 @@ public class WorkerHandler {
private WorkerHandler(@NonNull String name) { private WorkerHandler(@NonNull String name) {
mName = name; mName = name;
mThread = new HandlerThread(name); mThread = new HandlerThread(name) {
@NonNull
@Override
public String toString() {
return super.toString() + "[" + getThreadId() + "]";
}
};
mThread.setDaemon(true); mThread.setDaemon(true);
mThread.start(); mThread.start();
mHandler = new Handler(mThread.getLooper()); mHandler = new Handler(mThread.getLooper());

Loading…
Cancel
Save