Android 7.0經(jīng)驗(yàn)談:Dialog不顯示之迷

最近遇到個(gè)怪問(wèn)題,在其他手機(jī)上都能正常的顯示Dialog,但是在Android 7.0的手機(jī)上只能顯示Dialog的半透明背景,無(wú)法顯示Dialog的內(nèi)容。

用圖給大家展示一個(gè)遇到的現(xiàn)象,正常時(shí)應(yīng)該是這個(gè)樣子的:


而我們遇到的情況如下,更壞的是如果我們?cè)O(shè)置Dialog不能點(diǎn)擊空白處取消(dismiss),那么這個(gè)半透明背景一直覆蓋在Activity上面,只有通過(guò)殺進(jìn)程重新運(yùn)行應(yīng)用才能去掉它。

因?yàn)轫?xiàng)目工程比較大,排查這個(gè)問(wèn)題也花費(fèi)了很多時(shí)間。我最開(kāi)始時(shí)在Android 7.0寫一個(gè)Demo顯示Dialog發(fā)現(xiàn)是正常的,然后再在自己的框架上顯示Dialog發(fā)現(xiàn)也是正常的,說(shuō)明不是框架的問(wèn)題。

在測(cè)試了一些懷疑地方?jīng)]有效果后,只有用土辦法挨個(gè)排查了,兩個(gè)方向一個(gè)是不斷的注釋各個(gè)模塊看是否正常顯示,第二個(gè)是從正常開(kāi)始加上各個(gè)模塊看那個(gè)模塊代碼加上了出問(wèn)題。最后發(fā)現(xiàn)罪魁禍?zhǔn)资窍旅孢@段代碼:

        Resources resources = context.getResources();
        Configuration config = resources.getConfiguration();

        //解決修改系統(tǒng)字體大小時(shí),應(yīng)用頁(yè)面布局、字體等顯示或者排版混亂問(wèn)題
        config.setToDefaults();

在Application的onCreate方法會(huì)執(zhí)行這段代碼去設(shè)置資源的Configuration。再分析setToDefaults的源碼,主要是進(jìn)行了如下的初始化設(shè)置:

    /**
     * Set this object to the system defaults.
     */
    public void setToDefaults() {
        fontScale = 1;
        mcc = mnc = 0;
        locale = null;
        userSetLocale = false;
        touchscreen = TOUCHSCREEN_UNDEFINED;
        keyboard = KEYBOARD_UNDEFINED;
        keyboardHidden = KEYBOARDHIDDEN_UNDEFINED;
        hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED;
        navigation = NAVIGATION_UNDEFINED;
        navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
        orientation = ORIENTATION_UNDEFINED;
        screenLayout = SCREENLAYOUT_UNDEFINED;
        uiMode = UI_MODE_TYPE_UNDEFINED;
        screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
        screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
        smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
        densityDpi = DENSITY_DPI_UNDEFINED;
        seq = 0;
    }

其實(shí)看了一下很容易看出screenWidthDp和screenHeightDp比較可疑,測(cè)試了一下也確實(shí)是這兩個(gè)值被設(shè)置成0后(SCREEN_WIDTH_DP_UNDEFINED = 0)Dialog的內(nèi)容布局就無(wú)法顯示了。

那么,為什么同樣的代碼在Android 7.0之前的系統(tǒng)是好的呢?

我們知道Dialog本質(zhì)上也是一個(gè)PhoneWindow對(duì)像,顯示時(shí)被加到WindowManager,由WMS負(fù)責(zé)顯示。從DDMS的HierarchyView工具我們也可以看出,Dialog是一個(gè)PhoneWindow,且位于Activity的PhoneWindow之上,并且它的DecorView并不是全屏的。

在Android 7.0 DecorView被獨(dú)立成一個(gè)類DecorView.java,之前的版本是
PhoneWindow的內(nèi)部類,每次DecorView初始化時(shí)會(huì)進(jìn)行一個(gè)更新:

    private void updateAvailableWidth() {
        Resources res = getResources();
        mAvailableWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                res.getConfiguration().screenWidthDp, res.getDisplayMetrics());
    }

在這個(gè)方法里我們遇到了之前設(shè)置為0的res.getConfiguration().screenWidthDp,把DecorView的mAvailableWidth設(shè)置為0,自然無(wú)法看到Dialog的Layout內(nèi)容(寬度為0)。而7.0之前的版本并沒(méi)有這項(xiàng)設(shè)置。

疑問(wèn)

Activity的界面也是一個(gè)PhoneWindow,為什么screenWidthDp為0后Activity的Layout還是可以正常展示呢?如下圖所示,Activity的DecorView的寬并不是受screenWidthDp的影響。

從DecorView.java的onMeasure方法中我們看到,是否使用mAvailableWidth(updateAvailableWidth方法中賦值)還要看TypedValue的類型,可以判斷Dialog和Activity應(yīng)該是在這個(gè)類型上有所區(qū)別,使得這個(gè)設(shè)置對(duì)Activity沒(méi)有什么影響。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容