Toast or Safe Toast? (2024)

  在Toast与Snackbar的那点事儿这篇文章中,受益良多,翻看了自己项目,发现项目也有重构一份SafeToastManager来统一管理应用Toast的弹出,并且解决方案和美团的这篇文章竟然出奇的一致!由于项目的最高TargetSdk版本还是23,所以暂时还没用到后续提到的SnackBar。

  但是在翻看该篇文章的时候,发现作者有一处错误的地方,在作者解释Toast导致BadTokenException的时候,有说明到该奔溃主要集中在Android 5.0 -- Android 7.1.2的机型上,自己有翻看了源码并实践,发现这种说法是有问题的。

  经过试验发现,在Sdk25(Android 7.1)版本以下的机型上,是不会产生BadTokenException问题的,只有在Sdk版本为 25 的机型上,才有可能产生异常崩溃,因为在Android O(26)中,Google修复了此问题。

  Toast导致BadTokenException的原因详见Toast与Snackbar的那点事儿,其根本原因就是主线程Looper阻塞导致的异常,NMS会在固定时间之后移除生成的Token标识,而此时主线程由于阻塞没能及时的执行WindowManager.addView(),导致出现BadTokenException异常。在Android 7.1.1上,WMS执行addWindow()判断代码如下:

public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { .............. if (token == null) { .............. if (type == TYPE_TOAST) { // 注 : 此处判断的为 Target Sdk 版本是否大于 25 // Apps targeting SDK above N MR1 cannot arbitrary add toast windows. if (doesAddToastWindowRequireToken(attrs.packageName, callingUid, attachedWindow)) { Slog.w(TAG_WM, "Attempted to add a toast window with unknown token " + attrs.token + ". Aborting."); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } } } ...............}

  从上述可看出,在TargetSdk为25以上,当需要弹出一个window type为toast类型的弹窗时,首先需要强制判断Token是否存在。那么当一个toast弹出的时候,这个token是什么时候产生的呢。
  通过对Toast.show()的代码跟踪如下,最终会调用到NMS去管理Toast弹出,NMS维护一个toastRecord队列,依次弹出toast,代码如下:

 public void enqueueToast(String pkg, ITransientNotification callback, int duration) { if (DBG) { Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration); } if (pkg == null || callback == null) { Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); return ; } final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, Binder.getCallingUid()); if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid()) || isPackageSuspended)) { if (!isSystemToast) { Slog.e(TAG, "Suppressing toast from package " + pkg + (isPackageSuspended ? " due to package suspended by administrator." : " by user request.")); return; } } synchronized (mToastQueue) { int callingPid = Binder.getCallingPid(); long callingId = Binder.clearCallingIdentity(); try { ToastRecord record; int index = indexOfToastLocked(pkg, callback); // If it's already in the queue, we update it in place, we don't // move it to the end of the queue. if (index >= 0) { record = mToastQueue.get(index); record.update(duration); } else { // Limit the number of toasts that any given package except the android // package can enqueue. Prevents DOS attacks and deals with leaks. if (!isSystemToast) { int count = 0; final int N = mToastQueue.size(); for (int i=0; i<N; i++) { final ToastRecord r = mToastQueue.get(i); if (r.pkg.equals(pkg)) { count++; if (count >= MAX_PACKAGE_NOTIFICATIONS) { Slog.e(TAG, "Package has already posted " + count + " toasts. Not showing more. Package=" + pkg); return; } } } } // 产生一个新的Token 对象 source from android 7.1 // 注 : 从 Android 7.1 开始,才有的代码 Binder token = new Binder(); // 通知 WMS 去添加 Token mWindowManagerInternal.addWindowToken(token, WindowManager.LayoutParams.TYPE_TOAST); record = new ToastRecord(callingPid, pkg, callback, duration, token); // 将新生成的 ToastRecord 添加至 mToastQueue mToastQueue.add(record); index = mToastQueue.size() - 1; keepProcessAliveIfNeededLocked(callingPid); } // If it's at index 0, it's the current toast. It doesn't matter if it's // new or just been updated. Call back and tell it to show itself. // If the callback fails, this will remove it from the list, so don't // assume that it's valid after this. if (index == 0) { // 通知客户端去弹toast showNextToastLocked(); } } finally { Binder.restoreCallingIdentity(callingId); } } }

  从上述代码分析可知,在SDK 25版本及以上,产生ToastRecord时会强制生成一个Token,并且在 SDK 为25 的 WMS addWindow()的代码中,会强制判断当前Token是否有效(注:强制判断的条件为当前应用的 TargetSdk 版本是否大于 25),所以,即使在 Android 7.1 的手机上,如果应用的TargetSdk 版本在 26以下,也是不会有问题的。

  综上所述,唯一可能因为Token 不生效,而导致BadTokenException 的情况,只有可能是在Android 7.1 的机型上,但是安装应用的Target Sdk版本为26!

  在Android O(SDK 26)中,Google为此做了修复处理,具体代码参加Toast源码如下:

public void handleShow(IBinder windowToken) { ................... if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) { return; } if (mView != mNextView) { // remove the old view if necessary handleHide(); mView = mNextView; Context context = mView.getContext().getApplicationContext(); String packageName = mView.getContext().getOpPackageName(); if (context == null) { context = mView.getContext(); } mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); // We can resolve the Gravity here by using the Locale for getting // the layout direction final Configuration config = mView.getContext().getResources().getConfiguration(); final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection()); mParams.gravity = gravity; if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) { mParams.horizontalWeight = 1.0f; } if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) { mParams.verticalWeight = 1.0f; } mParams.x = mX; mParams.y = mY; mParams.verticalMargin = mVerticalMargin; mParams.horizontalMargin = mHorizontalMargin; mParams.packageName = packageName; mParams.hideTimeoutMilliseconds = mDuration == Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT; mParams.token = windowToken; if (mView.getParent() != null) { if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this); mWM.removeView(mView); } if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this); // Since the notification manager service cancels the token right // after it notifies us to cancel the toast there is an inherent // race and we may attempt to add a window after the token has been // invalidated. Let us hedge against that. // 注: Android O 在 windowmanager.addView()的时候,做了 try catch // 处理,手动捕获了异常 try { mWM.addView(mView, mParams); trySendAccessibilityEvent(); } catch (WindowManager.BadTokenException e) { /* ignore */ } } }

  Android O在 Toast 最终要展示的时候(即 mWM.addView())的时候,做了 try catch处理,手动捕获了 badTokenException 异常。

  那么如何打造一个Safe Toast 来规避Android 7.1可能遇到的问题呢,在Toast与Snackbar的那点事儿这篇文章中也已经写得很明白,将 NMS 管理Toast的代码移出来,形成一个自己的ToastManager,然后思路和Android O一致,在真正 addView() 的地方,加一个try catch去保护。至于后续文章中提到的为了适配 Android 7.1 而采用的SnackBar策略。自己觉得如果对应用自身TargetSdk版本没有特别高要求的话,可以暂时不升到26。这样的话,即使不try catch 的话,Android 7.1 也不会产生 BadTokenException问题。

参考文章:http://zhuanlan.51cto.com/art/201804/569585.htm

最后编辑于

©

著作权归作者所有,转载或内容合作请联系作者

  • 人面猴

    序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...

    沈念sama阅读 174,493评论 5赞 416

  • 死咒

    序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...

    沈念sama阅读 73,611评论 2赞 334

  • 救了他两次的神仙让他今天三更去死

    文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...

    开封第一讲书人阅读 123,360评论 0赞 288

  • 道士缉凶录:失踪的卖姜人

    文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...

    开封第一讲书人阅读 47,406评论 0赞 245

  • 港岛之恋(遗憾婚礼)

    正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...

    茶点故事阅读 56,176评论 3赞 325

  • 恶毒庶女顶嫁案:这布局不是一般人想出来的

    文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...

    开封第一讲书人阅读 42,743评论 1赞 241

  • 城市分裂传说

    那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...

    沈念sama阅读 33,832评论 3赞 355

  • 双鸳鸯连环套:你想象不到人心有多黑

    文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...

    开封第一讲书人阅读 32,406评论 0赞 228

  • 万荣杀人案实录

    序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...

    沈念sama阅读 36,439评论 1赞 269

  • 护林员之死

    正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...

    茶点故事阅读 32,120评论 2赞 275

  • 白月光启示录

    正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...

    茶点故事阅读 33,773评论 1赞 288

  • 活死人

    序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...

    沈念sama阅读 29,889评论 3赞 284

  • 日本核电站爆炸内幕

    正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...

    茶点故事阅读 35,050评论 3赞 279

  • 男人毒药:我在死后第九天来索命

    文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...

    开封第一讲书人阅读 27,059评论 0赞 11

  • 一桩弑父案,背后竟有这般阴谋

    文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...

    开封第一讲书人阅读 28,223评论 1赞 232

  • 情欲美人皮

    我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...

    沈念sama阅读 38,151评论 2赞 309

  • 代替公主和亲

    正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...

    茶点故事阅读 37,849评论 2赞 313

推荐阅读更多精彩内容

  • 拥有这些网址,将成为电脑高手!转载收藏吧

    http://www.huai235.com/网址大全http://www.quzhuanpan.com/ 转盘网...

    haoning7788阅读 389评论 0赞 8

  • 《通往财富自由之路》专栏留言版(七)

    落后 (一) “落后”这个观念,主要讲了这三个问题: ...

    一访文阅读 329评论 0赞 7

  • 从1.6W名面试者中收集的Java面试题精选汇总(内附知识脑图)

    本篇的面试题是接之前读者的要求,发出来的。 首先,声明下,以下知识点并非全部来自BAT的面试题。 如果觉得在本文中...

    程序员技术圈阅读 3,922评论 6赞 205

  • 假如我是一个妈妈,该如何安排自己的一切?

    之所以会想到这个主题,是因为看到一位读博的妈妈,凌晨5店雷打不动开始做功课,今年已经带着孩子上学了,由此,就明白一...

    海豚的世界阅读 124评论 0赞 0

  • 挑战通灵者究竟可不可信?

    最近迷上了俄罗斯综艺节目——《挑战通灵者》。这是一档尺度较大内容争议的真人秀,关于心灵、灵修、灵媒、宗教等,凡是身...

    林果儿shirley阅读 13,180评论 1赞 2

Toast or Safe Toast? (2024)

FAQs

Should I toast or not to toast? ›

Toast has been shown to have a lower glycemic index than bread that is untoasted. Although the difference isn't huge, toast has fewer carbohydrates than bread due to the chemical reaction that occurs.

Why toast instead of bread when sick? ›

Toast is easier to digest than bread as the toasting process breaks down some of the carbohydrates. Toast can help decrease nausea and reduce heartburn, but not all toast is the same. Whole wheat bread is more healthful than white bread but is high in fiber and can be difficult for some people to eat.

What to put on toast when sick? ›

She also suggests trying toast with egg whites, drinking bone broth, or having a smoothie, if you think you can tolerate it. “Keep it simple and don't force it if you feel like you cannot even look at food,” Cording says.

Why does toast help upset the stomach? ›

Toasted bread or plain crackers, like saltines, can help absorb excess stomach acid and relieve an upset stomach. Toast and crackers are also easy to digest, which can also help alleviate stomach upset.

How do you respond to toast? ›

Smile and make eye contact with the person who proposed the toast. Wait until everyone has had a chance to drink, then offer a brief response. Thank the person who proposed the toast and the guests for their kind words and support. Keep your response short and sincere.

Do you toast someone or toast to someone? ›

When you toast someone or something, you drink a toast to them. We all toasted his health.

Why is the BRAT diet no longer recommended? ›

However, many health professionals no longer recommend it due to the risk of nutrient and calorie deficiencies. The foods in the BRAT diet are low in protein, fat, and fiber, which makes them easy to digest for most people.

What are the hardest foods to digest? ›

What Are the Most Difficult Foods to Digest?
  1. 1 .Processed foods. The affordability and omnipresence of processed foods make our lives easier. ...
  2. Dairy. ...
  3. Alcohol. ...
  4. Artificial Sweeteners. ...
  5. Carb-Dense Foods. ...
  6. Excessive Raw Vegetables. ...
  7. Acidic Fruit. ...
  8. Caffeine.

What is the easiest food to digest? ›

Foods that are easier to digest include toast, white rice, bananas, eggs, chicken, salmon, gelatine, applesauce, and oatmeal.

Is peanut butter ok when sick? ›

A lack of protein can make nausea feel even worse, so look to protein-packed foods, such as nuts — even peanut butter, as long as you're not allergic — that are easy to digest. They'll quickly replenish your depleted energy and help keep your nausea at bay.

What 12 foods stop diarrhea? ›

What to Eat and Avoid on a Diarrhea Diet
  • White bread or toast.
  • Clear broth.
  • Coconut water.
  • Plain pasta.
  • White potato (peeled)
  • Bananas.
  • White rice.
  • Canned pears.
Sep 8, 2023

Is banana good for diarrhea? ›

Eat foods that are high in pectin, such as applesauce, bananas, and yogurt. Pectin, a water-soluble fiber, helps reduce diarrhea. Eat foods that have a lot of potassium, such as fruit juices, sports drinks, potatoes without the skin, and bananas.

Is scrambled egg on toast good for upset stomach? ›

Eggs. Prepared simply, eggs are one of the most easily digestible foods that you can eat to help ease nausea. Scrambled, poached or soft-boiled all do the trick, giving the body a lift of energy with minimal volume.

Why does milk calm my stomach? ›

Milk has a lower pH than the gastric acid that the stomach secretes for digestion. Therefore, it was formerly believed that milk would help ease the acidity of an upset stomach. It does for a few hours, by coating the stomach lining and acting as a buffer against excess acid.

What replaced the BRAT diet? ›

The use of cereals, rice and milk as a stop-gap eating plan for stomach upset has been validated as a more effective remedy to manage diarrhea than the BRAT diet by recent research in hospitals in South America and Asia.

Is toast better than not toasted? ›

And clinical dietitian Melanie Jones confirms that toasting bread does not change its calorie content. The difference is in digestibility. Nutritional site mindbodygreen.com says toasting breaks down the complex carbohydrate starch as the bread's water level decreases, making it easier to digest.

Is it necessary to toast bread? ›

If you suffer from obesity or diabetes, toast is beneficial to your health. Toasting bread helps to lessen its fat content. This fat decrease may not be evident during a meal, but if you consume toasted bread on a daily basis, this amount will be noticeable over time.

What is the etiquette for toasting? ›

The toast proposer should raise their glass and says the toast, ending with the name of the person/people/organisation that is being toasted. Everyone else then raises their glass, and repeats the name.

Why don't people toast their bread? ›

Toasted bread may contain benzo[a]pyrene and high levels of acrylamide, a carcinogen generated during the browning process. High acrylamide levels can also be found in other heated carbohydrate-rich foods. The darker the surface colour of the toast, the higher its concentration of acrylamide.

Top Articles
Latest Posts
Article information

Author: Catherine Tremblay

Last Updated:

Views: 5773

Rating: 4.7 / 5 (67 voted)

Reviews: 82% of readers found this page helpful

Author information

Name: Catherine Tremblay

Birthday: 1999-09-23

Address: Suite 461 73643 Sherril Loaf, Dickinsonland, AZ 47941-2379

Phone: +2678139151039

Job: International Administration Supervisor

Hobby: Dowsing, Snowboarding, Rowing, Beekeeping, Calligraphy, Shooting, Air sports

Introduction: My name is Catherine Tremblay, I am a precious, perfect, tasty, enthusiastic, inexpensive, vast, kind person who loves writing and wants to share my knowledge and understanding with you.