當前位置:菜譜大全網 - 素菜食譜大全 - 使用系統Toast時出現的問題

使用系統Toast時出現的問題

記錄使用系統Toast時出現的問題:

1.關閉通知權限時不顯示華為等手機的Toast

2.不同手機上吐司排隊機制可能不同;

3.Toast的BadTokenException問題;

當發現系統Toast有問題時,很多同學使用自定義TYPE_TOAST子彈框來達到同樣的效果。雖然在所有情況下效果都還可以,但TYPE_TOAST還是有問題:

4.token null在Android 8.0之後無效(部分機型實測);

5.Android 7.1以後,不允許同時顯示兩個TYPE_TOAST彈出框(部分型號問題實測);

所以解決方案是:

我相信很多同學老項目裏打包的ToastUtil直接用ApplicationContext作為上下文,然後在需要彈出窗口的時候直接用ToastUtil.show(str),這是我們使用起來最方便的方式。

當然,妳仍然可以用YToast使用這種打包方式,但是這種方式可能無法在下面的場景中成功顯示彈出窗口(原生Toast在這個場景中也無法彈出),但是請放心,不會導致應用崩潰,出現這個場景的概率很小,具備以下三個必要條件:

1.通知欄權限關閉(默認情況下,通知欄權限全部打開)。

2.非MIUI手機

3.3以上的部分手機。Android8.0(我最近測試的8.0+設備都沒有這個問題)。

但是如果想保證彈出窗口在所有場景下都能正常顯示,還是建議在YToast.make(context)的時候傳入Activity作為上下文,這樣YToast就會啟用ActivityToast在這個場景下顯示彈出窗口。

接下來詳細分析上面提到的五個問題。

看下面Toast源代碼中的show()方法,通過AIDL獲取Inovation Manager,將下壹個顯示過程的控制權交給INotificationManager服務。將在NMS中驗證Toast,當無法驗證通知權限時,將不顯示Toast。

當然,NMS在不同的rom中可能是不同的。比如MIUI就修改了這部分內容,所以小米手機關閉的通知權限不會導致Toast無法顯示。

如何解決這個問題?只要能繞過NotificationManagerService。

YToast通過使用TYPE_Toast實現全局彈出功能,不使用系統TOAST或NMS服務,因此不受通知權限的限制。

我找到了四個設備,創建了兩個不同重力的Toast並調用了show()方法。因此,有四種顯示效果:

出現這個問題的原因應該是NMS在各大廠商ROM中維護Toast隊列的邏輯不同。

同樣,YToast也維護自己的隊列邏輯,以保證在所有手機上使用DToast的效果是壹樣的。

當YToast中連續出現多個彈出窗口時:

優先級相同時,前壹個終止,後壹個直接顯示;

優先級不同,如果後壹個優先級更高,前壹個會終止,後壹個直接顯示。

windowToken在什麽情況下會失敗?

UI線程被阻塞,導致TN.show()沒有及時執行。當NotificationManager的檢測超時時,WMS中的令牌將被刪除,從而使令牌失效。

怎麽解決?

因此,我們需要對8.0之前的用戶進行同樣的操作。YToast通過反射完成此操作,如下所示:

Android8.0以後,WindowManager受到了限制和修改,特別是對於TYPE_TOAST的窗口,必須傳遞壹個令牌進行驗證。

API 25:(PhoneWindowManager.java源代碼)

API 26:(PhoneWindowManager.java源代碼)

為了解決第壹個問題,DovaToast不得不選擇繞過NotificationManagerService的控制,但是由於windowToken是由NMS生成的,繞過NMS無法獲得有效的windowToken,所以DovaToast作為TYPE_TOAST可能會陷入第四個問題。

所以DToast選擇在DovaToast出現這個問題的時候引入ActivityToast,在DovaToast無法正常顯示的時候創建壹個附加在Activity上的彈出窗口來顯示,但是ActivityToast只會顯示當前的活動,沒有跨頁功能。

如果有更好的解決方案,那壹定是獲取浮窗權限,然後切換到TYPE_PHONE,但是浮窗權限往往不容易獲取。目前恐怕除了微信,其他app都無法保證用戶的浮窗權限。

YToast的彈出策略是壹次只顯示壹個彈出窗口,邏輯上避免了這個問題。因此,只有這個異常被捕獲。

其他建議

如果可以接受Toast不跨接口,建議使用SnackBar。