返回

揭秘Toast内部:Android学习笔记14

Android

Toast:Android 中简短通知的幕后揭秘

引言:
在 Android 开发中,Toast 是一种不可或缺的组件,用于向用户提供简洁的通知信息。为了深入了解 Toast 的运作原理,本文将带领大家踏上源码分析之旅,揭示 Toast 的创建、显示和隐藏过程,以及 Handler 在其中扮演的关键角色。

1. Toast 的诞生

幕后黑手:makeToast() 方法
Toast 的诞生始于 makeToast() 方法。它需要两个参数:上下文(Context)和字符串(CharSequence),用于指定要显示的文本信息。

牵线搭桥:getService() 方法
makeToast() 方法首先创建 Toast 对象,然后调用 getService() 方法,用于获取 NotificationManagerService(NMS)。NMS 是 Android 系统管理通知服务的枢纽,而 Toast 本质上也是一种系统通知。

队列排队:enqueueToast() 方法
获得 NMS 后,show() 方法调用 enqueueToast() 方法,将 Toast 添加到 NMS 的队列中。此方法首先创建一个 Notification 对象,然后调用 enqueueToastEx() 方法将其添加到队列中。

细致调整:adjustNotificationTime() 方法
在 enqueueToastEx() 方法中,adjustNotificationTime() 方法负责调整通知时间。随后,sendNotification() 方法将通知发送到 NotificationManager,由后者负责将通知呈现在屏幕上。

2. Toast 的闪亮登场

后台操盘手:handleNotification() 方法
当 Toast 被发送到 NotificationManager 后,NotificationManager 会调用 handleNotification() 方法进行处理。此方法首先调用 handleToast() 方法,专门负责 Toast 的处理。

现身舞台:Toast.show() 方法
handleToast() 方法首先调用 Toast.show() 方法,让 Toast 正式登场。此方法首先调用 getWindowToken() 方法获取窗口令牌,然后调用 addToast() 方法将 Toast 添加到窗口中。

队列管理:ToastQueue
addToast() 方法将 Toast 添加到 ToastQueue 中,然后调用 updateToast() 方法更新 Toast 的状态。updateToast() 方法调用 updateToastVisibility() 方法更新 Toast 的可见性,然后调用 show() 方法显示 Toast。

预备展示:Toast.onPreDraw() 方法
show() 方法调用 Toast.onPreDraw() 方法,为 Toast 的绘制做准备。此方法首先调用 measure() 方法测量 Toast 的大小,然后调用 layout() 方法布局 Toast。

跃上舞台:addView() 方法
layout() 方法调用 getDecorView() 方法获取 DecorView,然后调用 addView() 方法将 Toast 添加到 DecorView 中。addView() 方法将 Toast 添加到视图树中,然后调用 invalidate() 方法请求重新绘制 DecorView。

闪亮登场:
当 DecorView 重新绘制后,Toast 就会闪亮登场,出现在屏幕上。

3. Toast 的谢幕演出

隐藏序幕:hide() 方法
当 Toast 完成使命时,可以调用 hide() 方法将其隐藏。hide() 方法首先调用 cancel() 方法取消 Toast。cancel() 方法调用 dequeueToast() 方法从 NMS 的队列中删除 Toast。

终场号令:finishToastLocked() 方法
dequeueToast() 方法调用 finishToastLocked() 方法完成 Toast 的隐藏。finishToastLocked() 方法调用 hide() 方法隐藏 Toast。hide() 方法将 Toast 从窗口中移除,然后调用 removeToast() 方法从 ToastQueue 中删除 Toast。

清理舞台:removeToast() 方法
removeToast() 方法调用 updateToastVisibility() 方法更新 Toast 的可见性,然后调用 hide() 方法隐藏 Toast。hide() 方法调用 Toast.onHide() 方法隐藏 Toast。onHide() 方法调用 Toast.onPostHide() 方法后完成隐藏。

谢幕演出:
onPostHide() 方法将 Toast 从视图树中移除,然后调用 invalidate() 方法请求重新绘制 DecorView。当 DecorView 重新绘制后,Toast 就从屏幕上消失了。

4. Handler 的穿针引线

主线程执政官:Handler.post() 方法
Handler 在 Toast 中主要负责处理 Toast 的显示和隐藏。当 Toast 需要显示时,show() 方法会调用 Handler.post() 方法,将 Toast 的显示任务添加到主线程的消息队列中。当主线程处理消息队列时,就会执行 Toast 的显示任务,将 Toast 显示在屏幕上。

幕后黑手:
同理,当 Toast 需要隐藏时,hide() 方法也会调用 Handler.post() 方法,将 Toast 的隐藏任务添加到主线程的消息队列中。当主线程处理消息队列时,就会执行 Toast 的隐藏任务,将 Toast 从屏幕上隐藏。

安全保障:
使用 Handler 可以确保 Toast 的显示和隐藏操作在主线程中执行,避免出现线程安全问题。

结论

通过对 Toast 源码的深入探究,我们了解了 Toast 的创建过程、显示过程和隐藏过程,以及 Handler 在其中不可或缺的作用。这些知识不仅加深了我们对 Android 通知机制的理解,更让我们能够更熟练地使用 Toast 组件,为用户提供清晰简洁的通知信息。

常见问题解答:

1. 如何自定义 Toast 的外观?
您可以通过调用 setGravity()、setBackground() 和 setDuration() 方法来自定义 Toast 的位置、背景和显示持续时间。

2. Toast 是否可以在后台线程中显示?
不可以。Toast 必须在主线程中显示,以避免线程安全问题。

3. 如何防止 Toast 重复显示?
可以使用 ToastQueue 来管理 Toast 的显示,确保在同一时间只显示一个 Toast。

4. Toast 是否支持 HTML?
不支持。Toast 仅支持显示纯文本信息。

5. 如何在 Toast 中显示图片?
可以使用自定义布局来在 Toast 中显示图片。