Android Toast cancel问题、源码分析和解决方案
本文中部分内容摘自API 部分代码来自android.widget.Toast类源代码
解决方案中 ToastUtil代码 由http://www.linuxidc.com/Linux/2012-01/51925.htm 修改而来(基本没做什么修改 删除了一个方法 添加了一个方法)
Toast介绍:
A toast is a view containing a quick little message for the user. The toast class helps you create and show those.
When the view is shown to the user, appears as a floating view over the application. It will never receive focus. The user will probably be in the middle of typing something else. The idea is to be as unobtrusive as possible, while still showing the user the information you want them to see. Two examples are the volume control, and the brief message saying that your settings have been saved.
The easiest way to use this class is to call one of the static methods that constructs everything you need and returns a new Toast object.
问题:
问题主要出现在通过按钮或事件触发Toast时,若多次点击按钮(或某事件多次触发),会触发一系列Toast,它们会依次缓慢出现在屏幕上,无法消除,令用户看起来很难受。
当然 Toast类中存在消除Toast的方法
public void cancel ()
Since: API Level 1
Close the view if it's showing, or don't show it if it isn't showing yet. You do not normally have to call this. Normally view will disappear on its own after the appropriate duration.
但是事实证明,API中对cancel类的说明完全是胡扯。
比如我在程序中存放一个ArrayList<Toast>对象用来存放所有的Toast对象,按照API的说法,即使我按了无数次的按钮触发了无数次Toast,但是只要遍历ArrayList 将全部Toast cancel掉不就一切都清净了?
遗憾的事,即使遍历ArrayList 对每一个Toast对象指向cancel方法,只有当前正在显示的Toast会被cancel掉,队列中的Toast的依然会依次展现。
查看下Toast类的源代码:
首先找到 cancel方法及相关调用链:
public void cancel() {
mTN.hide();
// TODO this still needs to cancel the inflight notification if any
}
/**
* schedule handleHide into the right thread
*/
public void hide() {
if (localLOGV) Log.v(TAG, "HIDE: " + this);
mHandler.post(mHide);
}
final Runnable mHide = new Runnable() {
public void run() {
handleHide();
}
};
public void handleHide() {
if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
if (mView != null) {
// note: checking parent() just to make sure the view has
// been added... i have seen cases where we get here when
// the view isn't yet added, so let's try not to crash.
if (mView.getParent() != null) {
if (localLOGV) Log.v(
TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
}
mView = null;
}
}
看到了么,源代码中显示,执行cancel方法 只会把正在显示的Toast移除,还未被显示的Toast,根本就通不过上面的if条件判断。
API中所说的 Close the view if it's showing, or don't show it if it isn't showing yet.
只有前半段是对的,后半段纯属胡扯。
解决方案:
由于Toast中控制显示 隐藏的部分private class TN extends ITransientNotification.Stub 是个私有内部类,所以继承Toast修改代码是不成了,也听说有高手用反射动态修改这部分的,不知解决情况究竟如何。
这里这个解决办法很简单,既然加入Toast队列的Toast我无法控制,我自己在外部实现一个Toast队列,自己控制它就是了。
简单的实现:全局只有1个Toast对象 由此类中的静态方法控制显示。
每次显示时,cancel掉原来的Toast对象。即,Toast队列中,只有0或1个Toast。每次触发Toast动作,都会立即清除上一个Toast.
package XXXXXXXXXXXXXXXXXXXXXX;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;
public class ToastUtil {
private static Handler handler = new Handler(Looper.getMainLooper());
private static Toast toast = null;
private static Object synObj = new Object();
public static void showMessage(final Context act, final String msg) {
showMessage(act, msg, Toast.LENGTH_SHORT);
}
public static void showMessage(final Context act, final int msg) {
showMessage(act, msg, Toast.LENGTH_SHORT);
}
public static void showMessage(final Context act, final int msg,
final int len) {
new Thread(new Runnable() {
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
synchronized (synObj) {
if (toast != null) {
toast.cancel();
toast.setText(msg);
toast.setDuration(len);
} else {
toast = Toast.makeText(act, msg, len);
}
toast.show();
}
}
});
}
}).start();
}
public static void cancelCurrentToast() {
if (toast != null) {
toast.cancel();
}
}
}
--------------------------
2月28日追加:
实测 在2.2 2.3中此方法工作良好。
在4.0系统中效果极差
多次触发Toast 无法正常显示
相关推荐
本篇文章将深入探讨如何在Android中自定义`Toast`的背景和添加图片,以实现更加个性化的用户体验。 首先,我们要了解`Toast`的基本用法。在Android中,我们可以通过`Toast.makeText()`方法来创建一个`Toast`实例,...
在Android开发中,`Toast`是一种轻量级的...通过以上方法,我们可以有效地解决`Toast`在Android应用中重复显示的问题,提高用户体验。在实际开发中,应根据具体场景选择合适的方法,遵循最佳实践,避免出现这类问题。
小米mimu系统,会对toast进行拦截,在用户提交的toast 消息体拼接一个前缀,由于该种会导致插件工程出现资源错乱,获取appLabel异常,现我们通过hook 动态代理,对消息发送做一个劫持,修改消息信息,还原原来的消息
Android Toast使用解析附代码,实现类似WEB开发中的弹出层效果,当用户点击一个链接或操作按钮时,会弹出一个操作层(浮动层)或浮动菜单,进而执行下一步操作。本源码是使用Android中的Toast对象来模拟实现网页中的...
最近在开发中我们经常会在适配5.0以后的机型遇到各种各样的问题,其中有一个不大不小的问题就是:Toast不显示问题,这篇文章就给大家总结了Android 5.0以上Toast不显示的原因与解决方法,有需要的朋友们可以参考借鉴...
在某些情况下,我们可能需要自定义Toast来实现更个性化的展示效果,解决系统Toast在样式、位置、持续时间等方面存在的限制。本文将深入探讨如何在Android中自定义Toast,并提供相应的代码示例。 首先,让我们了解...
Android 自定义 Toast 设定显示时间 Android 自定义 Toast 设定显示时间是指在 Android 应用程序中,自定义 Toast 的显示时间,而不是使用系统默认的 Toast.LENGTH_SHORT 或 Toast.LENGTH_LONG。本文将详细介绍如何...
标题提到的“Android Toast即便关闭了通知权限也会正常显示”是一个关键点,这涉及到Android系统的权限管理和Toast的工作原理。 首先,我们来了解`Android Toast`的基本使用。创建一个Toast非常简单,通常通过`...
在Android应用开发中,`AndroidToast`工具类是一种常见的组件,用于向用户显示短暂的通知信息。这些信息通常出现在屏幕上的某个位置,展示几秒钟后自动消失,不会干扰用户的正常操作。`AndroidToast`的使用非常方便...
关于`Toast`的源码分析,`Toast`类主要负责创建和管理显示的视图,而真正的显示工作是由`Toast$TN`(ToastTransport)这个内部类完成的。`TN`接口是系统服务`WindowManagerGlobal`所期望的,`Toast$TN`实现了该接口...
本篇将详细介绍如何自定义Toast以及解决重复出现的问题。 首先,自定义Toast主要涉及以下几个方面: 1. **创建布局文件**:在res/layout目录下创建一个XML布局文件,例如叫做`custom_toast.xml`。在这个文件中,你...
为了解决这个问题,开发者们通常会采取一些策略来优化`Toast`的显示。例如,创建一个全局的`Toast`实例,这样可以在需要显示新`Toast`时直接更新内容,而不是每次都创建新的`Toast`对象。下面是一个示例实现,即`...
以上就是`Android Toast`的基本使用方法,通过这些方式,开发者可以灵活地在应用中创建和定制`Toast`,以满足不同场景的需求。在实际开发中,结合DEMO进行实践,可以更好地理解和掌握`Toast`的用法。
本文将深入探讨这个问题,并提供一个解决方案——"Android-屏蔽系统通知Toast无法显示的解决方案v2.0.0"。 首先,理解Android系统的通知机制是至关重要的。Android的通知是由NotificationManager服务管理的,它允许...
### Android Toast 大全(五种情形) #### 一、概览 在Android开发中,`Toast`是一种轻量级的提示方式,主要用于快速显示简短的信息,如操作结果、临时提示等。它不会阻塞UI线程,也不需要用户进行任何交互即可...
"Android应用源码之自定义彩色Toast.zip"这个压缩包文件很可能是提供了一个示例项目,展示了如何在Android应用中实现自定义彩色Toast的功能。 自定义彩色Toast涉及的关键知识点包括: 1. **理解Toast的工作原理**...
在Android应用开发中,`Toast`是常用的轻量级提示组件,用于向用户展示短暂的信息。默认情况下,`Toast`的样式和位置都是系统固定的,但开发者可以根据需求自定义其样式和显示位置,以增强用户体验。本文将详细介绍...
全局Toast工具类,作用:连续显示toast提示时取消上一个toast 通过ToastUtil.toast(Context(), "文本")调用
在IT领域,尤其是在移动应用开发中,经常需要跨平台的解决方案。Qt是一个强大的跨平台应用程序开发框架,支持Windows、Linux、macOS、Android以及iOS等多个操作系统。本示例主要讲解如何在Qt应用中调用Android原生的...