家可以看到:在调用 callback.show
方法之后又调用了个 scheduleTimeoutLocked
方法:
record.callback.show(record.token);//通知进程显示scheduleTimeoutLocked(record);//超时监听消息
而这个方法就是用于管理 Toast
时序:
private void scheduleTimeoutLocked(ToastRecord r)
{
mHandler.removeCallbacksAndMessages(r);
Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
mHandler.sendMessageDelayed(m, delay);
}
scheduleTimeoutLocked
内部通过调用 Handler
的 sendMessageDelayed
函数来实现定时调用,而这个 mHandler
对象的实现类,是一个叫做 WorkerHandler
的内部类:
private final class WorkerHandler extends Handler
{
@Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case MESSAGE_TIMEOUT:
handleTimeout((ToastRecord)msg.obj);
break;
....
}
}
private void handleTimeout(ToastRecord record)
{
synchronized (mToastQueue) {
int index = indexOfToastLocked(record.pkg, record.callback);
if (index >= 0) {
cancelToastLocked(index);
}
}
}
WorkerHandler
处理 MESSAGE_TIMEOUT
消息会调用 handleTimeout(ToastRecord)
函数,而 handleTimeout(ToastRecord)
函数经过搜索后,将调用cancelToastLocked
函数取消掉 Toast
的显示:
void cancelToastLocked(int index) {
ToastRecord record = mToastQueue.get(index);
....
record.callback.hide();//远程调用hide,通知客户端隐藏窗口
....
ToastRecord lastToast = mToastQueue.remove(index);
mWindowManagerInternal.removeWindowToken(lastToast.token, true);
//将给 Toast 生成的窗口 Token 从 WMS 服务中删除
...
cancelToastLocked
函数将做以下两件事:
- 远程调用
ITransientNotification.hide
方法,通知客户端隐藏窗口 - 将给
Toast
生成的窗口Token
从WMS
服务中删除
上面我们就从源码的角度分析了一个Toast的显示和隐藏,我们不妨再来捋一下思路,Toast
的显示和隐藏大致分成以下核心步骤:
Toast
调用show
方法的时候 ,实际上是将自己纳入到NotificationManager
的Toast
管理中去,期间传递了一个本地的TN
类型或者是ITransientNotification.Stub
的Binder
对象NotificationManager
收到Toast
的显示请求后,将生成一个Binder
对象,将它作为一个窗口的token
添加到WMS
对象,并且类型是TOAST
NotificationManager
将这个窗口token
通过ITransientNotification
的show
方法传递给远程的TN
对象,并且抛出一个超时监听消息scheduleTimeoutLocked
TN
对象收到消息以后将往Handler
对象中post
显示消息,然后调用显示处理函数将Toast
中的View
添加到了WMS
管理中,Toast
窗口显示NotificationManager
的WorkerHandler
收到MESSAGE_TIMEOUT
消息,NotificationManager
远程调用进程隐藏Toast
窗口,然后将窗口token
从WMS
中删除