最近遇到個(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í)間。我最開始時(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è)是從正常開始加上各個(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)有什么影響灿意。