|
|
@ -47,467 +47,451 @@ import java.util.concurrent.locks.ReentrantLock; |
|
|
|
* |
|
|
|
* |
|
|
|
* Created by Dmytro Voronkevych on 17/06/2014. |
|
|
|
* Created by Dmytro Voronkevych on 17/06/2014. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@SuppressWarnings("unused") |
|
|
|
@SuppressWarnings("unused") public class WeakHandler { |
|
|
|
public class WeakHandler { |
|
|
|
private final Handler.Callback mCallback; |
|
|
|
private final Handler.Callback mCallback; // hard reference to Callback. We need to keep callback in memory
|
|
|
|
// hard reference to Callback. We need to keep callback in memory
|
|
|
|
private final ExecHandler mExec; |
|
|
|
private final ExecHandler mExec; |
|
|
|
private Lock mLock = new ReentrantLock(); |
|
|
|
private Lock mLock = new ReentrantLock(); |
|
|
|
@SuppressWarnings("ConstantConditions") |
|
|
|
@SuppressWarnings("ConstantConditions") @VisibleForTesting final ChainedRef mRunnables = |
|
|
|
@VisibleForTesting |
|
|
|
new ChainedRef(mLock, null); |
|
|
|
final ChainedRef mRunnables = new ChainedRef(mLock, null); |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Default constructor associates this handler with the {@link Looper} for the |
|
|
|
* Default constructor associates this handler with the {@link Looper} for the |
|
|
|
* current thread. |
|
|
|
* current thread. |
|
|
|
* |
|
|
|
* |
|
|
|
* If this thread does not have a looper, this handler won't be able to receive messages |
|
|
|
* If this thread does not have a looper, this handler won't be able to receive messages |
|
|
|
* so an exception is thrown. |
|
|
|
* so an exception is thrown. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public WeakHandler() { |
|
|
|
public WeakHandler() { |
|
|
|
mCallback = null; |
|
|
|
mCallback = null; |
|
|
|
mExec = new ExecHandler(); |
|
|
|
mExec = new ExecHandler(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Constructor associates this handler with the {@link Looper} for the |
|
|
|
|
|
|
|
* current thread and takes a callback interface in which you can handle |
|
|
|
|
|
|
|
* messages. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* If this thread does not have a looper, this handler won't be able to receive messages |
|
|
|
|
|
|
|
* so an exception is thrown. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param callback The callback interface in which to handle messages, or null. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public WeakHandler(@Nullable Handler.Callback callback) { |
|
|
|
|
|
|
|
mCallback = callback; // Hard referencing body
|
|
|
|
|
|
|
|
mExec = new ExecHandler(new WeakReference<>(callback)); // Weak referencing inside ExecHandler
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Use the provided {@link Looper} instead of the default one. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param looper The looper, must not be null. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public WeakHandler(@NonNull Looper looper) { |
|
|
|
|
|
|
|
mCallback = null; |
|
|
|
|
|
|
|
mExec = new ExecHandler(looper); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Use the provided {@link Looper} instead of the default one and take a callback |
|
|
|
|
|
|
|
* interface in which to handle messages. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param looper The looper, must not be null. |
|
|
|
|
|
|
|
* @param callback The callback interface in which to handle messages, or null. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public WeakHandler(@NonNull Looper looper, @NonNull Handler.Callback callback) { |
|
|
|
|
|
|
|
mCallback = callback; |
|
|
|
|
|
|
|
mExec = new ExecHandler(looper, new WeakReference<>(callback)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Causes the Runnable r to be added to the message queue. |
|
|
|
|
|
|
|
* The runnable will be run on the thread to which this handler is |
|
|
|
|
|
|
|
* attached. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param r The Runnable that will be executed. |
|
|
|
|
|
|
|
* @return Returns true if the Runnable was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean post(@NonNull Runnable r) { |
|
|
|
|
|
|
|
return mExec.post(wrapRunnable(r)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Causes the Runnable r to be added to the message queue, to be run |
|
|
|
|
|
|
|
* at a specific time given by <var>uptimeMillis</var>. |
|
|
|
|
|
|
|
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> |
|
|
|
|
|
|
|
* The runnable will be run on the thread to which this handler is attached. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param r The Runnable that will be executed. |
|
|
|
|
|
|
|
* @param uptimeMillis The absolute time at which the callback should run, |
|
|
|
|
|
|
|
* using the {@link android.os.SystemClock#uptimeMillis} time-base. |
|
|
|
|
|
|
|
* @return Returns true if the Runnable was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. Note that a |
|
|
|
|
|
|
|
* result of true does not mean the Runnable will be processed -- if |
|
|
|
|
|
|
|
* the looper is quit before the delivery time of the message |
|
|
|
|
|
|
|
* occurs then the message will be dropped. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) { |
|
|
|
|
|
|
|
return mExec.postAtTime(wrapRunnable(r), uptimeMillis); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Causes the Runnable r to be added to the message queue, to be run |
|
|
|
|
|
|
|
* at a specific time given by <var>uptimeMillis</var>. |
|
|
|
|
|
|
|
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> |
|
|
|
|
|
|
|
* The runnable will be run on the thread to which this handler is attached. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param r The Runnable that will be executed. |
|
|
|
|
|
|
|
* @param uptimeMillis The absolute time at which the callback should run, |
|
|
|
|
|
|
|
* using the {@link android.os.SystemClock#uptimeMillis} time-base. |
|
|
|
|
|
|
|
* @return Returns true if the Runnable was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. Note that a |
|
|
|
|
|
|
|
* result of true does not mean the Runnable will be processed -- if |
|
|
|
|
|
|
|
* the looper is quit before the delivery time of the message |
|
|
|
|
|
|
|
* occurs then the message will be dropped. |
|
|
|
|
|
|
|
* @see android.os.SystemClock#uptimeMillis |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) { |
|
|
|
|
|
|
|
return mExec.postAtTime(wrapRunnable(r), token, uptimeMillis); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Causes the Runnable r to be added to the message queue, to be run |
|
|
|
|
|
|
|
* after the specified amount of time elapses. |
|
|
|
|
|
|
|
* The runnable will be run on the thread to which this handler |
|
|
|
|
|
|
|
* is attached. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param r The Runnable that will be executed. |
|
|
|
|
|
|
|
* @param delayMillis The delay (in milliseconds) until the Runnable |
|
|
|
|
|
|
|
* will be executed. |
|
|
|
|
|
|
|
* @return Returns true if the Runnable was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. Note that a |
|
|
|
|
|
|
|
* result of true does not mean the Runnable will be processed -- |
|
|
|
|
|
|
|
* if the looper is quit before the delivery time of the message |
|
|
|
|
|
|
|
* occurs then the message will be dropped. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean postDelayed(Runnable r, long delayMillis) { |
|
|
|
|
|
|
|
return mExec.postDelayed(wrapRunnable(r), delayMillis); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Posts a message to an object that implements Runnable. |
|
|
|
|
|
|
|
* Causes the Runnable r to executed on the next iteration through the |
|
|
|
|
|
|
|
* message queue. The runnable will be run on the thread to which this |
|
|
|
|
|
|
|
* handler is attached. |
|
|
|
|
|
|
|
* <b>This method is only for use in very special circumstances -- it |
|
|
|
|
|
|
|
* can easily starve the message queue, cause ordering problems, or have |
|
|
|
|
|
|
|
* other unexpected side-effects.</b> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param r The Runnable that will be executed. |
|
|
|
|
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean postAtFrontOfQueue(Runnable r) { |
|
|
|
|
|
|
|
return mExec.postAtFrontOfQueue(wrapRunnable(r)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Remove any pending posts of Runnable r that are in the message queue. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final void removeCallbacks(Runnable r) { |
|
|
|
|
|
|
|
final WeakRunnable runnable = mRunnables.remove(r); |
|
|
|
|
|
|
|
if (runnable != null) { |
|
|
|
|
|
|
|
mExec.removeCallbacks(runnable); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
/** |
|
|
|
|
|
|
|
* Constructor associates this handler with the {@link Looper} for the |
|
|
|
/** |
|
|
|
* current thread and takes a callback interface in which you can handle |
|
|
|
* Remove any pending posts of Runnable <var>r</var> with Object |
|
|
|
* messages. |
|
|
|
* <var>token</var> that are in the message queue. If <var>token</var> is null, |
|
|
|
* |
|
|
|
* all callbacks will be removed. |
|
|
|
* If this thread does not have a looper, this handler won't be able to receive messages |
|
|
|
*/ |
|
|
|
* so an exception is thrown. |
|
|
|
public final void removeCallbacks(Runnable r, Object token) { |
|
|
|
* |
|
|
|
final WeakRunnable runnable = mRunnables.remove(r); |
|
|
|
* @param callback The callback interface in which to handle messages, or null. |
|
|
|
if (runnable != null) { |
|
|
|
*/ |
|
|
|
mExec.removeCallbacks(runnable, token); |
|
|
|
public WeakHandler(@Nullable Handler.Callback callback) { |
|
|
|
|
|
|
|
mCallback = callback; // Hard referencing body
|
|
|
|
|
|
|
|
mExec = new ExecHandler(new WeakReference<>(callback)); // Weak referencing inside ExecHandler
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Use the provided {@link Looper} instead of the default one. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param looper The looper, must not be null. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public WeakHandler(@NonNull Looper looper) { |
|
|
|
|
|
|
|
mCallback = null; |
|
|
|
|
|
|
|
mExec = new ExecHandler(looper); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
/** |
|
|
|
|
|
|
|
* Use the provided {@link Looper} instead of the default one and take a callback |
|
|
|
/** |
|
|
|
* interface in which to handle messages. |
|
|
|
* Pushes a message onto the end of the message queue after all pending messages |
|
|
|
* |
|
|
|
* before the current time. It will be received in callback, |
|
|
|
* @param looper The looper, must not be null. |
|
|
|
* in the thread attached to this handler. |
|
|
|
* @param callback The callback interface in which to handle messages, or null. |
|
|
|
* |
|
|
|
*/ |
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
public WeakHandler(@NonNull Looper looper, @NonNull Handler.Callback callback) { |
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
mCallback = callback; |
|
|
|
* looper processing the message queue is exiting. |
|
|
|
mExec = new ExecHandler(looper, new WeakReference<>(callback)); |
|
|
|
*/ |
|
|
|
} |
|
|
|
public final boolean sendMessage(Message msg) { |
|
|
|
|
|
|
|
return mExec.sendMessage(msg); |
|
|
|
/** |
|
|
|
} |
|
|
|
* Causes the Runnable r to be added to the message queue. |
|
|
|
|
|
|
|
* The runnable will be run on the thread to which this handler is |
|
|
|
/** |
|
|
|
* attached. |
|
|
|
* Sends a Message containing only the what value. |
|
|
|
* |
|
|
|
* |
|
|
|
* @param r The Runnable that will be executed. |
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
* |
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
* @return Returns true if the Runnable was successfully placed in to the |
|
|
|
* looper processing the message queue is exiting. |
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
*/ |
|
|
|
* looper processing the message queue is exiting. |
|
|
|
public final boolean sendEmptyMessage(int what) { |
|
|
|
*/ |
|
|
|
return mExec.sendEmptyMessage(what); |
|
|
|
public final boolean post(@NonNull Runnable r) { |
|
|
|
} |
|
|
|
return mExec.post(wrapRunnable(r)); |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Sends a Message containing only the what value, to be delivered |
|
|
|
|
|
|
|
* after the specified amount of time elapses. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. |
|
|
|
|
|
|
|
* @see #sendMessageDelayed(android.os.Message, long) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { |
|
|
|
|
|
|
|
return mExec.sendEmptyMessageDelayed(what, delayMillis); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Sends a Message containing only the what value, to be delivered |
|
|
|
|
|
|
|
* at a specific time. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. |
|
|
|
|
|
|
|
* @see #sendMessageAtTime(android.os.Message, long) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { |
|
|
|
|
|
|
|
return mExec.sendEmptyMessageAtTime(what, uptimeMillis); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Enqueue a message into the message queue after all pending messages |
|
|
|
|
|
|
|
* before (current time + delayMillis). You will receive it in |
|
|
|
|
|
|
|
* callback, in the thread attached to this handler. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. Note that a |
|
|
|
|
|
|
|
* result of true does not mean the message will be processed -- if |
|
|
|
|
|
|
|
* the looper is quit before the delivery time of the message |
|
|
|
|
|
|
|
* occurs then the message will be dropped. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean sendMessageDelayed(Message msg, long delayMillis) { |
|
|
|
|
|
|
|
return mExec.sendMessageDelayed(msg, delayMillis); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Enqueue a message into the message queue after all pending messages |
|
|
|
|
|
|
|
* before the absolute time (in milliseconds) <var>uptimeMillis</var>. |
|
|
|
|
|
|
|
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> |
|
|
|
|
|
|
|
* You will receive it in callback, in the thread attached |
|
|
|
|
|
|
|
* to this handler. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param uptimeMillis The absolute time at which the message should be |
|
|
|
|
|
|
|
* delivered, using the |
|
|
|
|
|
|
|
* {@link android.os.SystemClock#uptimeMillis} time-base. |
|
|
|
|
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. Note that a |
|
|
|
|
|
|
|
* result of true does not mean the message will be processed -- if |
|
|
|
|
|
|
|
* the looper is quit before the delivery time of the message |
|
|
|
|
|
|
|
* occurs then the message will be dropped. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { |
|
|
|
|
|
|
|
return mExec.sendMessageAtTime(msg, uptimeMillis); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Enqueue a message at the front of the message queue, to be processed on |
|
|
|
|
|
|
|
* the next iteration of the message loop. You will receive it in |
|
|
|
|
|
|
|
* callback, in the thread attached to this handler. |
|
|
|
|
|
|
|
* <b>This method is only for use in very special circumstances -- it |
|
|
|
|
|
|
|
* can easily starve the message queue, cause ordering problems, or have |
|
|
|
|
|
|
|
* other unexpected side-effects.</b> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean sendMessageAtFrontOfQueue(Message msg) { |
|
|
|
|
|
|
|
return mExec.sendMessageAtFrontOfQueue(msg); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Remove any pending posts of messages with code 'what' that are in the |
|
|
|
|
|
|
|
* message queue. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final void removeMessages(int what) { |
|
|
|
|
|
|
|
mExec.removeMessages(what); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Remove any pending posts of messages with code 'what' and whose obj is |
|
|
|
|
|
|
|
* 'object' that are in the message queue. If <var>object</var> is null, |
|
|
|
|
|
|
|
* all messages will be removed. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final void removeMessages(int what, Object object) { |
|
|
|
|
|
|
|
mExec.removeMessages(what, object); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Remove any pending posts of callbacks and sent messages whose |
|
|
|
|
|
|
|
* <var>obj</var> is <var>token</var>. If <var>token</var> is null, |
|
|
|
|
|
|
|
* all callbacks and messages will be removed. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final void removeCallbacksAndMessages(Object token) { |
|
|
|
|
|
|
|
mExec.removeCallbacksAndMessages(token); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Check if there are any pending posts of messages with code 'what' in |
|
|
|
|
|
|
|
* the message queue. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean hasMessages(int what) { |
|
|
|
|
|
|
|
return mExec.hasMessages(what); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Check if there are any pending posts of messages with code 'what' and |
|
|
|
|
|
|
|
* whose obj is 'object' in the message queue. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean hasMessages(int what, Object object) { |
|
|
|
|
|
|
|
return mExec.hasMessages(what, object); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public final Looper getLooper() { |
|
|
|
|
|
|
|
return mExec.getLooper(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private WeakRunnable wrapRunnable(@NonNull Runnable r) { |
|
|
|
|
|
|
|
//noinspection ConstantConditions
|
|
|
|
|
|
|
|
if (r == null) { |
|
|
|
|
|
|
|
throw new NullPointerException("Runnable can't be null"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
final ChainedRef hardRef = new ChainedRef(mLock, r); |
|
|
|
|
|
|
|
mRunnables.insertAfter(hardRef); |
|
|
|
|
|
|
|
return hardRef.wrapper; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
private static class ExecHandler extends Handler { |
|
|
|
* Causes the Runnable r to be added to the message queue, to be run |
|
|
|
private final WeakReference<Handler.Callback> mCallback; |
|
|
|
* at a specific time given by <var>uptimeMillis</var>. |
|
|
|
|
|
|
|
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> |
|
|
|
|
|
|
|
* The runnable will be run on the thread to which this handler is attached. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param r The Runnable that will be executed. |
|
|
|
|
|
|
|
* @param uptimeMillis The absolute time at which the callback should run, |
|
|
|
|
|
|
|
* using the {@link android.os.SystemClock#uptimeMillis} time-base. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Returns true if the Runnable was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. Note that a |
|
|
|
|
|
|
|
* result of true does not mean the Runnable will be processed -- if |
|
|
|
|
|
|
|
* the looper is quit before the delivery time of the message |
|
|
|
|
|
|
|
* occurs then the message will be dropped. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) { |
|
|
|
|
|
|
|
return mExec.postAtTime(wrapRunnable(r), uptimeMillis); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
ExecHandler() { |
|
|
|
* Causes the Runnable r to be added to the message queue, to be run |
|
|
|
mCallback = null; |
|
|
|
* at a specific time given by <var>uptimeMillis</var>. |
|
|
|
|
|
|
|
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> |
|
|
|
|
|
|
|
* The runnable will be run on the thread to which this handler is attached. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param r The Runnable that will be executed. |
|
|
|
|
|
|
|
* @param uptimeMillis The absolute time at which the callback should run, |
|
|
|
|
|
|
|
* using the {@link android.os.SystemClock#uptimeMillis} time-base. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Returns true if the Runnable was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. Note that a |
|
|
|
|
|
|
|
* result of true does not mean the Runnable will be processed -- if |
|
|
|
|
|
|
|
* the looper is quit before the delivery time of the message |
|
|
|
|
|
|
|
* occurs then the message will be dropped. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @see android.os.SystemClock#uptimeMillis |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) { |
|
|
|
|
|
|
|
return mExec.postAtTime(wrapRunnable(r), token, uptimeMillis); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
ExecHandler(WeakReference<Handler.Callback> callback) { |
|
|
|
* Causes the Runnable r to be added to the message queue, to be run |
|
|
|
mCallback = callback; |
|
|
|
* after the specified amount of time elapses. |
|
|
|
|
|
|
|
* The runnable will be run on the thread to which this handler |
|
|
|
|
|
|
|
* is attached. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param r The Runnable that will be executed. |
|
|
|
|
|
|
|
* @param delayMillis The delay (in milliseconds) until the Runnable |
|
|
|
|
|
|
|
* will be executed. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Returns true if the Runnable was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. Note that a |
|
|
|
|
|
|
|
* result of true does not mean the Runnable will be processed -- |
|
|
|
|
|
|
|
* if the looper is quit before the delivery time of the message |
|
|
|
|
|
|
|
* occurs then the message will be dropped. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean postDelayed(Runnable r, long delayMillis) { |
|
|
|
|
|
|
|
return mExec.postDelayed(wrapRunnable(r), delayMillis); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
ExecHandler(Looper looper) { |
|
|
|
* Posts a message to an object that implements Runnable. |
|
|
|
super(looper); |
|
|
|
* Causes the Runnable r to executed on the next iteration through the |
|
|
|
mCallback = null; |
|
|
|
* message queue. The runnable will be run on the thread to which this |
|
|
|
|
|
|
|
* handler is attached. |
|
|
|
|
|
|
|
* <b>This method is only for use in very special circumstances -- it |
|
|
|
|
|
|
|
* can easily starve the message queue, cause ordering problems, or have |
|
|
|
|
|
|
|
* other unexpected side-effects.</b> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param r The Runnable that will be executed. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean postAtFrontOfQueue(Runnable r) { |
|
|
|
|
|
|
|
return mExec.postAtFrontOfQueue(wrapRunnable(r)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
ExecHandler(Looper looper, WeakReference<Handler.Callback> callback) { |
|
|
|
* Remove any pending posts of Runnable r that are in the message queue. |
|
|
|
super(looper); |
|
|
|
*/ |
|
|
|
mCallback = callback; |
|
|
|
public final void removeCallbacks(Runnable r) { |
|
|
|
|
|
|
|
final WeakRunnable runnable = mRunnables.remove(r); |
|
|
|
|
|
|
|
if (runnable != null) { |
|
|
|
|
|
|
|
mExec.removeCallbacks(runnable); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@Override public void handleMessage(@NonNull Message msg) { |
|
|
|
* Remove any pending posts of Runnable <var>r</var> with Object |
|
|
|
if (mCallback == null) { |
|
|
|
* <var>token</var> that are in the message queue. If <var>token</var> is null, |
|
|
|
return; |
|
|
|
* all callbacks will be removed. |
|
|
|
} |
|
|
|
*/ |
|
|
|
final Handler.Callback callback = mCallback.get(); |
|
|
|
public final void removeCallbacks(Runnable r, Object token) { |
|
|
|
if (callback == null) { // Already disposed
|
|
|
|
final WeakRunnable runnable = mRunnables.remove(r); |
|
|
|
return; |
|
|
|
if (runnable != null) { |
|
|
|
} |
|
|
|
mExec.removeCallbacks(runnable, token); |
|
|
|
callback.handleMessage(msg); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
static class WeakRunnable implements Runnable { |
|
|
|
* Pushes a message onto the end of the message queue after all pending messages |
|
|
|
private final WeakReference<Runnable> mDelegate; |
|
|
|
* before the current time. It will be received in callback, |
|
|
|
private final WeakReference<ChainedRef> mReference; |
|
|
|
* in the thread attached to this handler. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean sendMessage(Message msg) { |
|
|
|
|
|
|
|
return mExec.sendMessage(msg); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
WeakRunnable(WeakReference<Runnable> delegate, WeakReference<ChainedRef> reference) { |
|
|
|
* Sends a Message containing only the what value. |
|
|
|
mDelegate = delegate; |
|
|
|
* |
|
|
|
mReference = reference; |
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean sendEmptyMessage(int what) { |
|
|
|
|
|
|
|
return mExec.sendEmptyMessage(what); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@Override public void run() { |
|
|
|
* Sends a Message containing only the what value, to be delivered |
|
|
|
final Runnable delegate = mDelegate.get(); |
|
|
|
* after the specified amount of time elapses. |
|
|
|
final ChainedRef reference = mReference.get(); |
|
|
|
* @see #sendMessageDelayed(android.os.Message, long) |
|
|
|
if (reference != null) { |
|
|
|
* |
|
|
|
reference.remove(); |
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
} |
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
if (delegate != null) { |
|
|
|
* looper processing the message queue is exiting. |
|
|
|
delegate.run(); |
|
|
|
*/ |
|
|
|
} |
|
|
|
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { |
|
|
|
|
|
|
|
return mExec.sendEmptyMessageDelayed(what, delayMillis); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
static class ChainedRef { |
|
|
|
* Sends a Message containing only the what value, to be delivered |
|
|
|
@Nullable ChainedRef next; |
|
|
|
* at a specific time. |
|
|
|
@Nullable ChainedRef prev; |
|
|
|
* @see #sendMessageAtTime(android.os.Message, long) |
|
|
|
@NonNull final Runnable runnable; |
|
|
|
* |
|
|
|
@NonNull final WeakRunnable wrapper; |
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { |
|
|
|
|
|
|
|
return mExec.sendEmptyMessageAtTime(what, uptimeMillis); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@NonNull Lock lock; |
|
|
|
* Enqueue a message into the message queue after all pending messages |
|
|
|
|
|
|
|
* before (current time + delayMillis). You will receive it in |
|
|
|
|
|
|
|
* callback, in the thread attached to this handler. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. Note that a |
|
|
|
|
|
|
|
* result of true does not mean the message will be processed -- if |
|
|
|
|
|
|
|
* the looper is quit before the delivery time of the message |
|
|
|
|
|
|
|
* occurs then the message will be dropped. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean sendMessageDelayed(Message msg, long delayMillis) { |
|
|
|
|
|
|
|
return mExec.sendMessageDelayed(msg, delayMillis); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
public ChainedRef(@NonNull Lock lock, @NonNull Runnable r) { |
|
|
|
* Enqueue a message into the message queue after all pending messages |
|
|
|
this.runnable = r; |
|
|
|
* before the absolute time (in milliseconds) <var>uptimeMillis</var>. |
|
|
|
this.lock = lock; |
|
|
|
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> |
|
|
|
this.wrapper = new WeakRunnable(new WeakReference<>(r), new WeakReference<>(this)); |
|
|
|
* You will receive it in callback, in the thread attached |
|
|
|
|
|
|
|
* to this handler. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param uptimeMillis The absolute time at which the message should be |
|
|
|
|
|
|
|
* delivered, using the |
|
|
|
|
|
|
|
* {@link android.os.SystemClock#uptimeMillis} time-base. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. Note that a |
|
|
|
|
|
|
|
* result of true does not mean the message will be processed -- if |
|
|
|
|
|
|
|
* the looper is quit before the delivery time of the message |
|
|
|
|
|
|
|
* occurs then the message will be dropped. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { |
|
|
|
|
|
|
|
return mExec.sendMessageAtTime(msg, uptimeMillis); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
public WeakRunnable remove() { |
|
|
|
* Enqueue a message at the front of the message queue, to be processed on |
|
|
|
lock.lock(); |
|
|
|
* the next iteration of the message loop. You will receive it in |
|
|
|
try { |
|
|
|
* callback, in the thread attached to this handler. |
|
|
|
if (prev != null) { |
|
|
|
* <b>This method is only for use in very special circumstances -- it |
|
|
|
prev.next = next; |
|
|
|
* can easily starve the message queue, cause ordering problems, or have |
|
|
|
|
|
|
|
* other unexpected side-effects.</b> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return Returns true if the message was successfully placed in to the |
|
|
|
|
|
|
|
* message queue. Returns false on failure, usually because the |
|
|
|
|
|
|
|
* looper processing the message queue is exiting. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean sendMessageAtFrontOfQueue(Message msg) { |
|
|
|
|
|
|
|
return mExec.sendMessageAtFrontOfQueue(msg); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Remove any pending posts of messages with code 'what' that are in the |
|
|
|
|
|
|
|
* message queue. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final void removeMessages(int what) { |
|
|
|
|
|
|
|
mExec.removeMessages(what); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Remove any pending posts of messages with code 'what' and whose obj is |
|
|
|
|
|
|
|
* 'object' that are in the message queue. If <var>object</var> is null, |
|
|
|
|
|
|
|
* all messages will be removed. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final void removeMessages(int what, Object object) { |
|
|
|
|
|
|
|
mExec.removeMessages(what, object); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Remove any pending posts of callbacks and sent messages whose |
|
|
|
|
|
|
|
* <var>obj</var> is <var>token</var>. If <var>token</var> is null, |
|
|
|
|
|
|
|
* all callbacks and messages will be removed. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final void removeCallbacksAndMessages(Object token) { |
|
|
|
|
|
|
|
mExec.removeCallbacksAndMessages(token); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Check if there are any pending posts of messages with code 'what' in |
|
|
|
|
|
|
|
* the message queue. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean hasMessages(int what) { |
|
|
|
|
|
|
|
return mExec.hasMessages(what); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Check if there are any pending posts of messages with code 'what' and |
|
|
|
|
|
|
|
* whose obj is 'object' in the message queue. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public final boolean hasMessages(int what, Object object) { |
|
|
|
|
|
|
|
return mExec.hasMessages(what, object); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public final Looper getLooper() { |
|
|
|
|
|
|
|
return mExec.getLooper(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private WeakRunnable wrapRunnable(@NonNull Runnable r) { |
|
|
|
|
|
|
|
//noinspection ConstantConditions
|
|
|
|
|
|
|
|
if (r == null) { |
|
|
|
|
|
|
|
throw new NullPointerException("Runnable can't be null"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
final ChainedRef hardRef = new ChainedRef(mLock, r); |
|
|
|
|
|
|
|
mRunnables.insertAfter(hardRef); |
|
|
|
|
|
|
|
return hardRef.wrapper; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static class ExecHandler extends Handler { |
|
|
|
|
|
|
|
private final WeakReference<Handler.Callback> mCallback; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ExecHandler() { |
|
|
|
|
|
|
|
mCallback = null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ExecHandler(WeakReference<Handler.Callback> callback) { |
|
|
|
|
|
|
|
mCallback = callback; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ExecHandler(Looper looper) { |
|
|
|
|
|
|
|
super(looper); |
|
|
|
|
|
|
|
mCallback = null; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (next != null) { |
|
|
|
ExecHandler(Looper looper, WeakReference<Handler.Callback> callback) { |
|
|
|
next.prev = prev; |
|
|
|
super(looper); |
|
|
|
|
|
|
|
mCallback = callback; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public void handleMessage(@NonNull Message msg) { |
|
|
|
|
|
|
|
if (mCallback == null) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
final Handler.Callback callback = mCallback.get(); |
|
|
|
|
|
|
|
if (callback == null) { // Already disposed
|
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
callback.handleMessage(msg); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
prev = null; |
|
|
|
|
|
|
|
next = null; |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
lock.unlock(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return wrapper; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static class WeakRunnable implements Runnable { |
|
|
|
public void insertAfter(@NonNull ChainedRef candidate) { |
|
|
|
private final WeakReference<Runnable> mDelegate; |
|
|
|
lock.lock(); |
|
|
|
private final WeakReference<ChainedRef> mReference; |
|
|
|
try { |
|
|
|
|
|
|
|
if (this.next != null) { |
|
|
|
WeakRunnable(WeakReference<Runnable> delegate, WeakReference<ChainedRef> reference) { |
|
|
|
this.next.prev = candidate; |
|
|
|
mDelegate = delegate; |
|
|
|
|
|
|
|
mReference = reference; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
candidate.next = this.next; |
|
|
|
public void run() { |
|
|
|
this.next = candidate; |
|
|
|
final Runnable delegate = mDelegate.get(); |
|
|
|
candidate.prev = this; |
|
|
|
final ChainedRef reference = mReference.get(); |
|
|
|
} finally { |
|
|
|
if (reference != null) { |
|
|
|
lock.unlock(); |
|
|
|
reference.remove(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (delegate != null) { |
|
|
|
|
|
|
|
delegate.run(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static class ChainedRef { |
|
|
|
@Nullable public WeakRunnable remove(Runnable obj) { |
|
|
|
@Nullable |
|
|
|
lock.lock(); |
|
|
|
ChainedRef next; |
|
|
|
try { |
|
|
|
@Nullable |
|
|
|
ChainedRef curr = this.next; // Skipping head
|
|
|
|
ChainedRef prev; |
|
|
|
while (curr != null) { |
|
|
|
@NonNull |
|
|
|
if (curr.runnable == obj) { // We do comparison exactly how Handler does inside
|
|
|
|
final Runnable runnable; |
|
|
|
return curr.remove(); |
|
|
|
@NonNull |
|
|
|
} |
|
|
|
final WeakRunnable wrapper; |
|
|
|
curr = curr.next; |
|
|
|
|
|
|
|
|
|
|
|
@NonNull |
|
|
|
|
|
|
|
Lock lock; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ChainedRef(@NonNull Lock lock, @NonNull Runnable r) { |
|
|
|
|
|
|
|
this.runnable = r; |
|
|
|
|
|
|
|
this.lock = lock; |
|
|
|
|
|
|
|
this.wrapper = new WeakRunnable(new WeakReference<>(r), new WeakReference<>(this)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public WeakRunnable remove() { |
|
|
|
|
|
|
|
lock.lock(); |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
if (prev != null) { |
|
|
|
|
|
|
|
prev.next = next; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (next != null) { |
|
|
|
|
|
|
|
next.prev = prev; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
prev = null; |
|
|
|
|
|
|
|
next = null; |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
lock.unlock(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return wrapper; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void insertAfter(@NonNull ChainedRef candidate) { |
|
|
|
|
|
|
|
lock.lock(); |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
if (this.next != null) { |
|
|
|
|
|
|
|
this.next.prev = candidate; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
candidate.next = this.next; |
|
|
|
|
|
|
|
this.next = candidate; |
|
|
|
|
|
|
|
candidate.prev = this; |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
lock.unlock(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
|
|
|
public WeakRunnable remove(Runnable obj) { |
|
|
|
|
|
|
|
lock.lock(); |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
ChainedRef curr = this.next; // Skipping head
|
|
|
|
|
|
|
|
while (curr != null) { |
|
|
|
|
|
|
|
if (curr.runnable == obj) { // We do comparison exactly how Handler does inside
|
|
|
|
|
|
|
|
return curr.remove(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
curr = curr.next; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
lock.unlock(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
lock.unlock(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |