[原创]Android Handler使用Message的一个注意事项

最近发现了一个莫名其妙的问题,在使用Handler.post(Runnable)这个接口时,Runnable有时候没有运行,非常奇怪,后来发现是因为调用Handler.removeMessage()时,what参数传的0,导致Runnable所在的Message被remove了,下面看下源码。

     class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_SOME:
Log.i("zhoukewen", "what ==== 0........");
break;
}
}
} Handler h = new MyHandler(); final int MSG_DO_SOME = 0; public void onStartClick(View view) { h.sendEmptyMessage(MSG_DO_SOME);
h.post(new Runnable() {
@Override
public void run() {
Log.i("zhoukewen", "runnable............");
}
});
h.removeMessages(MSG_DO_SOME);
}

情景大概如图所示,开发者也许希望删除what=MSG_DO_SOME的msg,但当SG_DO_SOME恰好等于0时,会连带携带Runnable的msg也被删除,我们看下post源码:

先看Handler.java

    public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
} private final Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}

再看Message.obtain()

    public int what;

    public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}

可以看到,post(Runnable)时实际上也是创建一个Message,从代码中看到,该Message要不就是从sPool池中获取,要不就是new出来的,如果new出来的,其成员变量自然被初始化为0。如果从sPool中获取的话,sPool中的Message都是经过recycle()之后才能使用的,我们看源码:

    public void recycle() {
clearForRecycle(); synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
} /*package*/ void clearForRecycle() {
flags = 0;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
when = 0;
target = null;
callback = null;
data = null;
}

果然也是设置为0。所以,Handler.post(Runnable)其实就是生成一个what为0的Message,而当remove时,会删除所有what为0的Message,也就是吧Runnable的Message删除了,所以导致了之前看到的诡异问题。

上一篇:Zabbix的安装与部署---问题处理(php65.6.28 mysqli 报错误 处理)


下一篇:关于PHPstorm 使用技巧