如何通過getApplicationContext()返回的context創(chuàng)建一個(gè)Dialog

android的window一共分為三個(gè)級(jí)別,包括應(yīng)用級(jí)別的窗口,系統(tǒng)級(jí)別的窗口以及子窗口。其中dialog就屬于應(yīng)用級(jí)別的窗口。我們在使用dialog的時(shí)候,都知道dialog需要傳入activity作為構(gòu)建dialog的context。但是如果傳入getApplicationContext,就會(huì)報(bào)錯(cuò)Unable to add window -- token null is not for an application。那么是不是就只能傳入activity了呢?其實(shí)也不是。對話框拋出“無法添加窗口 – 令牌null不適用于應(yīng)用程序”與 getApplication()作為上下文這篇文章一共列出了十種解決方案,我們這里主要就是討論通過將應(yīng)用級(jí)別的dialog提升為系統(tǒng)級(jí)別的window,來解決傳入getApplicationContext()的問題。

一:通過window設(shè)置setType,提升window級(jí)別

系統(tǒng)window的級(jí)別從2000-2999不等

Dialog dialog=new Dialog(getApplicationContext());
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
TextView textView=new TextView(this);
textView.setText("Hello");
dialog.setContentView(textView);
dialog.show();

之后我們還需要在AndroidMenifest.xml中添加一個(gè)權(quán)限,不然就會(huì)出現(xiàn)下面這樣的異常。

Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@d87e9e4 -- permission denied for this window type

需要添加的權(quán)限

 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

至此我們在其他手機(jī)上,就都可以通過傳入getApplicationContext來解決彈出dialog的問題了,但是在小米手機(jī)上卻總是彈不出來。

二:小米手機(jī)彈出自定義系統(tǒng)window。

在小米手機(jī)上,我們需要手動(dòng)設(shè)置彈出系統(tǒng)window的權(quán)限,應(yīng)用才可以彈出系統(tǒng)級(jí)別的window,具體設(shè)置方法是設(shè)置-->授權(quán)管理-->應(yīng)用權(quán)限管理-->選擇自己的app-->勾選顯示懸浮窗

2017-06-15 09_53_43.gif

經(jīng)過上面的操作,設(shè)置懸浮窗權(quán)限成功,就可以正確彈出系統(tǒng)級(jí)window。

三:通過運(yùn)行時(shí)判斷是否是小米系統(tǒng)解決miui無法彈出系統(tǒng)對話框問題

除了通過上述方法提示用戶來設(shè)置系統(tǒng)級(jí)別window的權(quán)限問題,我們還可以通過代碼判斷是否是miui,這樣我們就單獨(dú)對miui做另外的處理。下面的方法,雖然沒有設(shè)置懸浮窗權(quán)限,但是依然能夠彈出系統(tǒng)級(jí)別的window。這是因?yàn)橥ㄟ^windownManager為dialog設(shè)置了setType。

 public void get_dialog(View view){
        Dialog dialog=new Dialog(getApplicationContext());
        TextView textView=new TextView(this);
        if(isMIUIRom()){
            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
            textView.setText("Hello xiaomi");

        }else{
            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
            textView.setText("Hello not xiaomi");

        }
        dialog.setContentView(textView);
        dialog.show();
    }

    public  boolean isMIUIRom(){
        String property =getSystemProperty("ro.miui.ui.version.name");
        return !TextUtils.isEmpty(property);
    }

    public  String getSystemProperty(String propName) {
        String line;
        BufferedReader input = null;
        try {
            Process p = Runtime.getRuntime().exec("getprop " + propName);
            input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
            line = input.readLine();
            input.close();
        } catch (IOException ex) {
            return null;
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                }
            }
        }
        return line;
    }

四:應(yīng)用級(jí)別的dialog為什么離開acitivty的token就活不下去了?

詳情可以參考騰訊一位同學(xué)寫的博客淺析Android的窗口
。文章分析的很詳細(xì),這里就不重復(fù)了。簡要把這篇文章的大意記錄一下。
前面我們提到了窗口分為三種:
(1):應(yīng)用級(jí)別窗口,比如Activity。 Dialog 的窗口類型也是是 TYPE _ APPLICATION
(2):子窗口,比如PopupWindow。
(3):系統(tǒng)級(jí)別窗口,比如Toast。
其中應(yīng)用類型窗口,子窗口,以及部分系統(tǒng)窗口,都是需要token的,而其他一些系統(tǒng)窗口則可以不需要token。這里需要token的系統(tǒng)窗口類型如TYPE _ INPUT _ METHOD,TYPE _ VOICE _ INTERACTION,TYPE _ WALLPAPER,TYPE _ DREAM,TYPE _ ACCESSIBILITY _ OVERLAY。

image.png

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容