|
// ------------------------------------------------------------------------------------------ |
|
// This work is licensed under Creative Commons Attribution-ShareAlike license version 2.5. |
|
// |
|
// * Author: que |
|
// * License |
|
// * Legal code: https://creativecommons.org/licenses/by-sa/2.5/legalcode |
|
// * Summary: https://creativecommons.org/licenses/by-sa/2.5/ |
|
// * Original work |
|
// * Author: StackOverflow |
|
// * URL: https://stackoverflow.com/questions/8040280/how-to-handle-handler-messages-when-activity-fragment-is-paused# |
|
// * Changes: This work has been changed from the original work. |
|
// ------------------------------------------------------------------------------------------ |
|
package que; |
|
|
|
import android.os.Handler; |
|
import android.os.Message; |
|
import android.support.annotation.GuardedBy; |
|
import android.support.annotation.NonNull; |
|
import android.support.annotation.Nullable; |
|
import android.support.annotation.UiThread; |
|
|
|
import java.util.LinkedList; |
|
import java.util.Queue; |
|
|
|
/** |
|
* PauseHandler for {@link Handler#post(Runnable)}. |
|
*/ |
|
public class PauseHandler extends Handler { |
|
private final Object mIsPauseLocker = new Object(); |
|
private final Object mStoresMessagesLocker = new Object(); |
|
@GuardedBy("mIsPauseLocker") |
|
private boolean mIsPause; |
|
@GuardedBy("mStoresMessagesLocker") |
|
private final boolean mStoresMessages; |
|
@NonNull |
|
private final Queue<Message> mQueue = new LinkedList<>(); |
|
|
|
/** |
|
* Create an instance. Queued messages are saved while {@link #onPause()} is called to |
|
* {@link #onResume()} is called. |
|
*/ |
|
public PauseHandler() { |
|
this(true); |
|
} |
|
|
|
/** |
|
* Create an instance and set a callback. |
|
* Queued messages are saved while {@link #onPause()} is called to |
|
* {@link #onResume()} is called. |
|
* |
|
* @param callback The callback. The instance does not callback if {@code null} is set. |
|
*/ |
|
public PauseHandler(@Nullable final Callback callback) { |
|
this(callback, true); |
|
} |
|
|
|
/** |
|
* Create an instance. |
|
* |
|
* @param storesMessages When {@code true} is set messages are saved, |
|
* otherwise the messages are destroyed. |
|
*/ |
|
public PauseHandler(final boolean storesMessages) { |
|
super(); |
|
mStoresMessages = storesMessages; |
|
} |
|
|
|
/** |
|
* Create an instance. |
|
* |
|
* @param callback The callback. The instance does not callback if {@code null} is set. |
|
* @param storesMessages When {@code true} is set messages are saved, |
|
* otherwise the messages are destroyed. |
|
*/ |
|
public PauseHandler(@Nullable final Callback callback, |
|
final boolean storesMessages) { |
|
super(callback); |
|
mStoresMessages = storesMessages; |
|
} |
|
|
|
/** |
|
* When this method is called saved messages are re-sent. |
|
*/ |
|
@UiThread |
|
public void onResume() { |
|
setPause(false); |
|
|
|
while (!mQueue.isEmpty()) { |
|
final Message msg = mQueue.poll(); |
|
if (msg != null) { |
|
sendMessage(msg); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* After this method is called requested messages will be saved or destroyed. |
|
*/ |
|
@UiThread |
|
public void onPause() { |
|
setPause(true); |
|
} |
|
|
|
/** |
|
* When this method is called saved messages are destroyed and recycled. |
|
*/ |
|
@UiThread |
|
public void onDestroy() { |
|
while (!mQueue.isEmpty()) { |
|
final Message msg = mQueue.poll(); |
|
if (msg != null) { |
|
msg.recycle(); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* {@inheritDoc} |
|
* |
|
* @param msg |
|
*/ |
|
@UiThread |
|
@Override |
|
public void dispatchMessage(final Message msg) { |
|
if (isPause()) { |
|
if (msg != null && storesMessages()) { |
|
final Message copied = Message.obtain(msg); |
|
mQueue.offer(copied); |
|
} |
|
} else { |
|
super.dispatchMessage(msg); |
|
} |
|
} |
|
|
|
private boolean storesMessages() { |
|
synchronized (mStoresMessagesLocker) { |
|
return mStoresMessages; |
|
} |
|
} |
|
|
|
private void setPause(final boolean isPause) { |
|
synchronized (mIsPauseLocker) { |
|
mIsPause = isPause; |
|
} |
|
} |
|
|
|
private boolean isPause() { |
|
synchronized (mIsPauseLocker) { |
|
return mIsPause; |
|
} |
|
} |
|
|
|
/** |
|
* {@link android.app.Activity#runOnUiThread(Runnable)} like utility method. |
|
* <p> |
|
* This method behave like {@link android.app.Activity#runOnUiThread(Runnable)}, |
|
* so an action is executed on the UI thread. |
|
* When {@link #onPause()} is called the action is destroyed or |
|
* saved until {@link #onResume()} is called. |
|
* |
|
* @param action the action to run on the UI thread |
|
*/ |
|
public void runOnUiThreadSafely(@NonNull final Runnable action) { |
|
final boolean isUiThread = Thread.currentThread() == getLooper().getThread(); |
|
final boolean isPause = isPause(); |
|
if (isUiThread && !isPause) { |
|
action.run(); |
|
} else { |
|
post(action); |
|
} |
|
} |
|
} |