工作5年才知道的Android新版本使用Toast的那些坑,已给你总结好

工作5年才知道的Android新版本使用Toast的那些坑,已给你总结好华为 三星等机型禁用通知权限后 Toast 不弹出原因查看 Toast 源码后发现 Toast 显示 要通过 INotificatio 类来实现 而当通知禁用后 调用此类会返回异常 所以导致通知不显示 源码如下 publicvoidsh

大家好,欢迎来到IT知识分享网。

华为、三星等机型禁用通知权限后Toast不弹出

原因

查看Toast源码后发现,Toast显示要通过INotificationManager类来实现,而当通知禁用后,调用此类会返回异常,所以导致通知不显示,源码如下:

public void show() { if (mNextView == null) { throw new RuntimeException("setView must have been called"); } INotificationManager service = getService(); String pkg = mContext.getOpPackageName(); TN tn = mTN; tn.mNextView = mNextView; try { service.enqueueToast(pkg, tn, mDuration); } catch (RemoteException e) { // 权限禁用后走这里,这里是空方法,所以会发生既不crash又无响应的情况 } }
工作5年才知道的Android新版本使用Toast的那些坑,已给你总结好

这是一个google的bug,部分小米手机重写了Toast代码,所以可以正常执行,我们可以通过反射的方式来暴力绕过,也就有了如下解决方式

解决方法

public class ToastUtils { private static Object iNotificationManagerObj; / * @param context * @param message */ public static void show(Context context, String message) { show(context.getApplicationContext(), message, Toast.LENGTH_SHORT); } / * @param context * @param message */ public static void show(Context context, String message, int duration) { if (TextUtils.isEmpty(message)) { return; } //后setText 兼容小米默认会显示app名称的问题 Toast toast = Toast.makeText(context, null, duration); toast.setText(message); if (isNotificationEnabled(context)) { toast.show(); } else { showSystemToast(toast); } } / * 显示系统Toast */ private static void showSystemToast(Toast toast) { try { Method getServiceMethod = Toast.class.getDeclaredMethod("getService"); getServiceMethod.setAccessible(true); //hook INotificationManager if (iNotificationManagerObj == null) { iNotificationManagerObj = getServiceMethod.invoke(null); Class iNotificationManagerCls = Class.forName("android.app.INotificationManager"); Object iNotificationManagerProxy = Proxy.newProxyInstance(toast.getClass().getClassLoader(), new Class[]{iNotificationManagerCls}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //强制使用系统Toast if ("enqueueToast".equals(method.getName()) || "enqueueToastEx".equals(method.getName())) { //华为p20 pro上为enqueueToastEx args[0] = "android"; } return method.invoke(iNotificationManagerObj, args); } }); Field sServiceFiled = Toast.class.getDeclaredField("sService"); sServiceFiled.setAccessible(true); sServiceFiled.set(null, iNotificationManagerProxy); } toast.show(); } catch (Exception e) { e.printStackTrace(); } } / * 消息通知是否开启 * * @return */ private static boolean isNotificationEnabled(Context context) { NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context); boolean areNotificationsEnabled = notificationManagerCompat.areNotificationsEnabled(); return areNotificationsEnabled; } }
工作5年才知道的Android新版本使用Toast的那些坑,已给你总结好

内容相同Toast短时间不能重复弹出

原因

当我们重复点击Toast时候,会连续弹出很多Toast,视觉体验不好,于是网上流传着这些解决方法:

Toast mToast; public void showToast(String text) { if (mToast == null) { mToast = Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT); } else { mToast.setText(text); mToast.setDuration(Toast.LENGTH_SHORT); } mToast.show(); }

这个方法在旧版本android上没有问题,新版本当短时间显示同一个Toast时,会显示不出来。

文字相同且当前Toast正在显示时,系统会认为是误触操作,从而屏蔽当前显示Toast请求。

出现这个问题据说是为了防止某些流氓app一直弹出一个模仿系统界面的Toast从而导致系统瘫痪。

解决方法

这是系统的限制,想要绕过这个限制只能自定义Toast了,这里我推荐git上的大神自定义版Toast——XToast

https://github.com/getActivity/XToast

文章不易,如果大家喜欢这篇文章,或者对你有帮助希望大家多多,点赞,转发,关注 哦。文章会持续更新的。绝对干货!!!

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/181315.html

(0)
上一篇 2025-06-19 10:20
下一篇 2025-06-19 10:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信