|
|
@ -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,14 +43,19 @@ 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); |
|
|
|
|
|
|
|
sCache.remove(name); |
|
|
|
} |
|
|
|
} |
|
|
|
LOG.w("get:", "Thread reference died, removing.", name); |
|
|
|
|
|
|
|
sCache.remove(name); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LOG.i("get:", "Creating new handler.", name); |
|
|
|
LOG.i("get:", "Creating new handler.", 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(); |
|
|
|