關於懸浮窗設置TYPE_TOAST崩潰的問題
- 最近在做項目有用到懸浮窗,發現了一個問題,WindowManager.LayoutParams的屬性設置爲TYPE_TOAST在安卓7.1.1系統出現崩潰。在使用Type Toast懸浮窗的同時,使用了Toast,必現崩潰,即使catch 了Throwable也無法解決,但是假如什麼都沒做則不會崩潰,不過幾秒後就消失了
查了一下資料發現在安卓7.1.1的系統上谷歌限制了開發者對TYPE_TOAST的濫用
google在該版本開始對TYPE TOAST進行管控,防止一個應用的懸浮窗一直懸浮在另一個應用上造成干擾
// If adding a toast requires a token for this app we always schedule hiding
// toast windows to make sure they don't stick around longer then necessary.
// We hide instead of remove such windows as apps aren't prepared to handle
// windows being removed under them.
//
// If the app is older it can add toasts without a token and hence overlay
// other apps. To be maximally compatible with these apps we will hide the
// window after the toast timeout only if the focused window is from another
// UID, otherwise we allow unlimited duration. When a UID looses focus we
// schedule hiding all of its toast windows.
if (type == TYPE_TOAST) {
if (!getDefaultDisplayContentLocked().canAddToastWindowForUid(callingUid)) {
Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
// Make sure this happens before we moved focus as one can make the
// toast focusable to force it not being hidden after the timeout.
// Focusable toasts are always timed out to prevent a focused app to
// show a focusable toasts while it has focus which will be kept on
// the screen after the activity goes away.
if (addToastWindowRequiresToken
|| (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0
|| mCurrentFocus == null
|| mCurrentFocus.mOwnerUid != callingUid) {
mH.sendMessageDelayed(
mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
win.mAttrs.hideTimeoutMilliseconds);
}
}
從源碼可以看出假如添加了TYPE_TOAST,則顯示,並且設置了延遲消息,延遲時間爲hideTimeoutMilliseconds
時間到了則強制隱藏
case WINDOW_HIDE_TIMEOUT:{
final windowState window = (WindowState)msg.obj;
synchronized(mWindowMap){
window.mAttrs.flags &= ~FLAG_KEEP_SCREEN_ON;
window.hidePermanentlyLw();
window.setDisplayLayoutNeeded();
mWindowPlacerLocked.performSurfacePlacement();
}
}
break;
時間到了強制隱藏~
我這裏解決的方案是判斷系統,如果大於7.0的話則使用TYPE_SYSTEM_ALERT來顯示
//設置type,系統提示型窗口,在應用程序之上
if (FloatPermissionChecker.checkSDKVersion()) {
mParmas!!.type = WindowManager.LayoutParams.TYPE_TOAST
} else {
mParmas!!.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
}
這樣的話就需要手動去開啓設置裏面的懸浮窗開關,我們代碼裏面可以這麼寫去引導用戶打開懸浮窗
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
//這句是重點,可以調到對應的應用界面裏
intent.data = Uri.parse("package:" + context.activity!!.packageName)
context.startActivityForResult(intent, DeveloperComponent.PERMISSION_REQUEST, null, listener)
然後通過Settings.canDrawOverlays(application)來判斷應用是否授權了懸浮窗顯示權限。