
记录下在使用系统Toast存在的问题:
1. 当通知权限被关闭时华为等手机Toast不显示
2. Toast队列机制上在不同手机上可能不同
3. Toast的BadTokenException问题
当发现系统Toast存在问题时,不少同学使用自定义TYPE_TOASTd框来实现相同效果.虽然情况下效果都是OK的,但TYPE_TOAST依然会存在问题:
4. Android8.0之后的token null is not valid问题(实测部分机型问题)
5. Android7.1之后,不允许同时展示两个TYPE_TOASTd窗(实测部分机型问题)
那么解决方案是:
相信不少同学旧项目中封装的迹纤ToastUtil都是直接使用的ApplicationContext作为上下文,然后在需要d窗的时候直接就是ToastUtil.show(str),这样的使用方式对于我们来说是最方便的啦。
当然,使用YToast你也依然可以沿用这种封装方式,但这种方式在下面这个场景中可能会无法成功展示出d窗(该场景下原生Toast也一样无法d出),不过请放心不会导致应用崩溃,而且这个场景出现的概率较小,有以下三个必要条件:
1.通知栏权限被关闭(通知栏权限默认都是打开的)
2.非MIUI手机
3.Android8.0以上的部分手机(我最近测试中的几部8.0+设备都不存在该问题)。
不过,如果想要保证在所有场景下都能正常展示d窗,还是建议在YToast.make(context)时传入Activity作为上下文,这样在该场景下YToast会启用ActivityToast展示出d窗。
接下来再详细分析下上面提到的五个问题洞州乱。
看下方Toast源码中的show()方法,通过AIDL获取到INotificationManager,并将接下来的显示流程控制权交给NotificationManagerService。NMS中会对Toast进行权限校验,当通知权限校验不通过时,Toast将不做展示。
当然不同ROM中NMS可能会有不同,比如MIUI就对这部分内容进行了修改,所以小米手机关闭通知权限不会导致Toast不显示。
如何解决这个问题?只要能够绕过NotificationManagerService即可。
YToast通过使用TYPE_TOAST实现全局d窗功能,不使用系统Toast,也没有使用NMS服务,因此不受通知权限限制。
我找了四台设备,创建两个Gravity不同的Toast并调用show()方法,结果出现纳档了四种展示效果:
造成这个问题的原因应该是各大厂商ROM中NMS维护Toast队列的逻辑有差异。
同样的,YToast内部也维护着自己的队列逻辑,保证在所有手机上使用DToast的效果相同。
YToast中多个d窗连续出现时:
相同优先级时,会终止上一个,直接展示后一个;
不同优先级时,如果后一个的优先级更高则会终止上一个,直接展示后一个。
什么情况下windowToken会失效?
UI线程发生阻塞,导致TN.show()没有及时执行,当NotificationManager的检测超时后便会删除WMS中的该token,即造成token失效。
如何解决?
因此对于8.0之前的我们也需要做相同的处理。YToast是通过反射完成这个动作,具体看下方实现:
Android8.0后对WindowManager做了限制和修改,特别是TYPE_TOAST类型的窗口,必须要传递一个token用于校验。
API25:(PhoneWindowManager.java源码)
API26:(PhoneWindowManager.java源码)
为了解决问题一,DovaToast不得不选择绕过NotificationManagerService的控制,但由于windowToken是NMS生成的,绕过NMS就无法获取到有效的windowToken,于是作为TYPE_TOAST的DovaToast就可能陷入第四个问题。
因此,DToast选择在DovaToast出现该问题时引入ActivityToast,在DovaToast无法正常展示时创建一个依附于Activity的d窗展示出来,不过ActivityToast只会展示在当前Activity,不具有跨页面功能。
如果说有更好的方案,那肯定是去获取悬浮窗权限然后改用TYPE_PHONE等类型,但悬浮窗权限往往不容易获取,目前来看恐怕除了微信其他APP都不能保证拿得到用户的悬浮窗权限。
YToast的d窗策略就是同一时间最多只展示一个d窗,逻辑上就避免了此问题。因此仅捕获该异常。
其他建议
如果能够接受Toast不跨界面的话,建议使用SnackBar
官方给做世的路径是这样import Toast from 'path/to/@vant/weapp/dist/toast/toast'磨缺
然后报错
修改后
import Toast from '@vant/瞎胡辩weapp/toast/toast'
可以正常使用了
*** 作某一个事件之后,发现浏览器一直执行某个方法,会一直请求后台接口,那核知就是栈溢出了,
解决的办法就是,执行完了,toast之后要clear:
let toast = Toast({
message:"提交成功",
type:"success",
逗旦 forbidClick:true,
})
setTimeout(()=>{
toast.clear()
this.$emit("山氏扰change")
},1000)
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)