Reuse fallback WorkerHandler

pull/528/head
Mattia Iavarone 6 years ago
parent bba869680b
commit 356b52de36
  1. 4
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/engine/CameraIntegrationTest.java
  2. 2
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/internal/utils/WorkerHandlerTest.java
  3. 52
      cameraview/src/main/java/com/otaliastudios/cameraview/internal/utils/WorkerHandler.java

@ -86,7 +86,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
@Before @Before
public void setUp() { public void setUp() {
LOG.e("Test started. Setting up camera."); LOG.e("Test started. Setting up camera.");
WorkerHandler.destroy(); WorkerHandler.destroyAll();
uiSync(new Runnable() { uiSync(new Runnable() {
@Override @Override
@ -126,7 +126,7 @@ public abstract class CameraIntegrationTest extends BaseTest {
public void tearDown() { public void tearDown() {
LOG.e("Test ended. Tearing down camera."); LOG.e("Test ended. Tearing down camera.");
camera.destroy(); camera.destroy();
WorkerHandler.destroy(); WorkerHandler.destroyAll();
} }
private void waitForUiException() throws Throwable { private void waitForUiException() throws Throwable {

@ -218,7 +218,7 @@ public class WorkerHandlerTest extends BaseTest {
public void testDestroy() { public void testDestroy() {
final WorkerHandler handler = WorkerHandler.get("handler"); final WorkerHandler handler = WorkerHandler.get("handler");
assertTrue(handler.getThread().isAlive()); assertTrue(handler.getThread().isAlive());
WorkerHandler.destroy(); WorkerHandler.destroyAll();
// Wait for the thread to die. // Wait for the thread to die.
try { handler.getThread().join(500); } catch (InterruptedException ignore) {} try { handler.getThread().join(500); } catch (InterruptedException ignore) {}
assertFalse(handler.getThread().isAlive()); assertFalse(handler.getThread().isAlive());

@ -25,6 +25,13 @@ public class WorkerHandler {
private final static CameraLogger LOG = CameraLogger.create(WorkerHandler.class.getSimpleName()); private final static CameraLogger LOG = CameraLogger.create(WorkerHandler.class.getSimpleName());
private final static ConcurrentHashMap<String, WeakReference<WorkerHandler>> sCache = new ConcurrentHashMap<>(4); private final static ConcurrentHashMap<String, WeakReference<WorkerHandler>> sCache = new ConcurrentHashMap<>(4);
private final static String FALLBACK_NAME = "FallbackCameraThread";
// Store a hard reference to the fallback handler. We never use this, only update it
// anytime get() is called. This should ensure that this instance is not collected.
@SuppressWarnings("FieldCanBeLocal")
private static WorkerHandler sFallbackHandler;
/** /**
* Gets a possibly cached handler with the given name. * Gets a possibly cached handler with the given name.
* @param name the handler name * @param name the handler name
@ -36,15 +43,20 @@ public class WorkerHandler {
//noinspection ConstantConditions //noinspection ConstantConditions
WorkerHandler cached = sCache.get(name).get(); WorkerHandler cached = sCache.get(name).get();
if (cached != null) { if (cached != null) {
HandlerThread thread = cached.mThread; if (cached.getThread().isAlive() && !cached.getThread().isInterrupted()) {
if (thread.isAlive() && !thread.isInterrupted()) {
LOG.w("get:", "Reusing cached worker handler.", name); LOG.w("get:", "Reusing cached worker handler.", name);
return cached; return cached;
} else {
// Cleanup the old thread before creating a new one
cached.destroy();
LOG.w("get:", "Thread reference found, but not alive or interrupted. Removing.", name);
sCache.remove(name);
} }
} } else {
LOG.w("get:", "Thread reference died, removing.", name); LOG.w("get:", "Thread reference died. Removing.", name);
sCache.remove(name); sCache.remove(name);
} }
}
LOG.i("get:", "Creating new handler.", name); LOG.i("get:", "Creating new handler.", name);
WorkerHandler handler = new WorkerHandler(name); WorkerHandler handler = new WorkerHandler(name);
@ -58,7 +70,8 @@ public class WorkerHandler {
*/ */
@NonNull @NonNull
public static WorkerHandler get() { public static WorkerHandler get() {
return get("FallbackCameraThread"); sFallbackHandler = get(FALLBACK_NAME);
return sFallbackHandler;
} }
/** /**
@ -183,6 +196,7 @@ public class WorkerHandler {
* Returns the android backing {@link Looper}. * Returns the android backing {@link Looper}.
* @return the looper * @return the looper
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull @NonNull
public Looper getLooper() { public Looper getLooper() {
return mThread.getLooper(); return mThread.getLooper();
@ -197,21 +211,35 @@ public class WorkerHandler {
return mExecutor; return mExecutor;
} }
/**
* Destroys this handler and its thread. After this method returns, the handler
* should be considered unusable.
*
* Internal note: this does not remove the thread from our cache, but it does
* interrupt it, so the next {@link #get(String)} call will remove it.
* In any case, we only store weak references.
*/
@SuppressWarnings("WeakerAccess")
public void destroy() {
HandlerThread thread = getThread();
if (thread.isAlive()) {
thread.interrupt();
thread.quit();
// after quit(), the thread will die at some point in the future. Might take some ms.
// try { handler.getThread().join(); } catch (InterruptedException ignore) {}
}
}
/** /**
* Destroys all handlers, interrupting their work and * Destroys all handlers, interrupting their work and
* removing them from our cache. * removing them from our cache.
*/ */
public static void destroy() { public static void destroyAll() {
for (String key : sCache.keySet()) { for (String key : sCache.keySet()) {
WeakReference<WorkerHandler> ref = sCache.get(key); WeakReference<WorkerHandler> ref = sCache.get(key);
//noinspection ConstantConditions //noinspection ConstantConditions
WorkerHandler handler = ref.get(); WorkerHandler handler = ref.get();
if (handler != null && handler.getThread().isAlive()) { if (handler != null) handler.destroy();
handler.getThread().interrupt();
handler.getThread().quit();
// after quit(), the thread will die at some point in the future. Might take some ms.
// try { handler.getThread().join(); } catch (InterruptedException ignore) {}
}
ref.clear(); ref.clear();
} }
sCache.clear(); sCache.clear();

Loading…
Cancel
Save