Android Handler.removeMessage移除所有postDelayed的问题
Posted 苦逼程序员_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Handler.removeMessage移除所有postDelayed的问题相关的知识,希望对你有一定的参考价值。
android Handler.removeMessage暗坑
在Android开发中,Handler的使用应该是比较多的,可以用它在UI线程中进行操作,也可以很方便的使用delay延时动作。
Handler的延时操作分两种:
1.延时执行一个可运行任务
- Handler.postDelayed(runnable, 10000)
2.延时发送一条Message消息
- Handler.sendEmptyMessageDelayed(0, 10000)
今天开发中遇到一个诡异的问题,handler.removeMessage(0)把所有的延时执行可运行任务都移除掉了,按照这个api的注释来看,应该是移除指定msg.what的延时消息才对。为什么会把其他的可执行任务都移除掉了?
接下来我们来创建一个自定义Handler
class MyHandler extends Handler
@Override
public void handleMessage(Message msg)
super.handleMessage(msg);
Log.d(TAG, "handleMessage: "+msg.what);
然后再创建两个自定义Runnable
Runnable runnable1 = new Runnable()
@Override
public void run()
Log.d(TAG, "run: 1");
;
Runnable runnable2 = new Runnable()
@Override
public void run()
Log.d(TAG, "run: 2");
;
然后开始执行handler的操作
MyHandler handler = new MyHandler();
handler.postDelayed(runnable1,2000);
handler.postDelayed(runnable2,2000);
handler.sendEmptyMessageDelayed(0,2000);
handler.sendEmptyMessageDelayed(1,2000);
handler.sendEmptyMessageDelayed(2,2000);
handler.removeMessages(0);
最后看一下打印出来的log
D/MainActivity: handleMessage: 1
D/MainActivity: handleMessage: 2
可以看到只有1和2两条延时发送的Message打印出来了,另外3个延时操作全部被取消掉,这里面果然有坑
那只有看看源码到底是怎么回事了
/**
* Remove any pending posts of messages with code 'what' that are in the
* message queue.
*/
public final void removeMessages(int what)
mQueue.removeMessages(this, what, null);
/**
* 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)
mQueue.removeMessages(this, what, object);
看到源码中实际调用了api的mQueue.removeMessages
,并且注释中解释了参数的作用,移除指定msg.what的消息,如果指定了object对象并且该object存在消息队列中则只移除该object。如果object是null,则移除消息队列中所有msg.what等于what参数的消息。
看这段api的注释,好像并没有什么问题,继续查找Handler.postDelayed
的源码
/**
* 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.
* <b>The time-base is @link android.os.SystemClock#uptimeMillis.</b>
* Time spent in deep sleep will add an additional delay to execution.
*
* @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 sendMessageDelayed(getPostMessage(r), delayMillis);
/**
* Enqueue a message into the message queue after all pending messages
* before (current time + delayMillis). You will receive it in
* @link #handleMessage, 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)
if (delayMillis < 0)
delayMillis = 0;
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
可以看到postDelayed内部调用了sendMessageDelayed方法!也就是说postDelayed的本质也是使Handler发送Message消息。而Message对象的创建则在getPostMessage(r)
方法中。继续往下看
private static Message getPostMessage(Runnable r)
Message m = Message.obtain();
m.callback = r;
return m;
public final class Message implements Parcelable
public int what;
...
/** Constructor (but the preferred way to get a Message is to call @link #obtain() Message.obtain()).
*/
public Message()
...
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain()
synchronized (sPoolSync)
if (sPool != null)
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
return new Message();
getPostMessage
方法通过Message.obtain()
获得了一个Message对象,并且把可运行任务绑定到message.callback中。通过上面Message源码注释可以了解,obtain()会从Message池中返回一个新的Message对象,再看Message的构造方法,空空如也。
所以问题找到了,一个新的Message对象,它的what变量默认为0!
这就解释了为什么handler.removeMessage(0)会把所有可执行任务都移除掉。
避开removeMessage暗坑方法:
1.自定义handler处理的msg.what消息不要使用默认值0
2.同一个handler不要同时使用postDelayed()和postMessageDelayed()两个方法
以上是关于Android Handler.removeMessage移除所有postDelayed的问题的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向Android 权限 ( Android 逆向中使用的 android.permission 权限 | Android 系统中的 Linux 用户权限 )