我所理解的PhoneWindow的一個作用

轉(zhuǎn)載自blog.csdn.net/u013356254/article/details/55116259

android交流:364595326

android中我們常見的Activity,Diaog等內(nèi)部都封裝了PhoneWindow對象。

我們今天要探討的是兩個問題

為什么系統(tǒng)在創(chuàng)建Acivity或者Dialog的時候封裝了PhoneWindow對象,而我們自己寫懸浮窗口的時候并沒有使用PhoneWindow對象?

為什么Diaog封裝了PhoneWindow對象揣非,而PopupWindow卻直接將contentView封裝成PopupDecorView(FrameLayout子類),直接調(diào)用WM來添加view?

我們從Dialog的setContentView()方法說起繁涂。源碼

public void setContentView(@NonNull View view, @Nullable ViewGroup.LayoutParams params) {

// 調(diào)用的是window的方法

mWindow.setContentView(view, params);

}

下面是PhoneWindow的setContentView()方法衡招。

@Override

public void setContentView(int layoutResID ) {

// mContentParent是id為ID_ANDROID_CONTENT的FrameLayout

// 我們經(jīng)常寫的setContentView第练,這個方法阔馋,其實就是給id為ID_ANDROID_CONTENT的view添加一個孩子

if (mContentParent == null) {

// 下面這個方法。完成了兩件事情

// 1 創(chuàng)建DecorView(FrameLayout),也就是我們經(jīng)常說的window中有個DecorView對象娇掏。

// 2 給mContentParent賦值

installDecor();

} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

// 如果沒有5.0轉(zhuǎn)場動畫呕寝,remove掉之前添加的所有view

mContentParent.removeAllViews();

}

if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

//? 5.0專場動畫

view.setLayoutParams(params);

final Scene newScene = new Scene(mContentParent, view);

transitionTo(newScene);

} else {

// 給id為ID_ANDROID_CONTENT的view添加新的孩子

// 將layoutResID添加到ContentParent上面

mLayoutInflater.inflate(layoutResID, mContentParent);

}

}

PhoneWindow.setContentView()方法的核心是,生成DecorView和mContentParent對象婴梧,之后將布局文件添加到mContentParent上面去

接下來我們分析installDecor()方法

private void installDecor() {

mForceDecorInstall = false;

if (mDecor == null) {

// 產(chǎn)生decorView 也就是ViewTree的根節(jié)點

mDecor = generateDecor(-1);

} else {

// 將decorView和window關(guān)聯(lián)起來

mDecor.setWindow(this);

}

if (mContentParent == null) {

// 根據(jù)decorview產(chǎn)生我們的ContentParent也就是id為content的viewGroup,

mContentParent = generateLayout(mDecor);

}

}

我們可以看到installDecor()方法主要是創(chuàng)建了DecorView下梢,和mContentParent對象客蹋。

下面是generateDecor(-1)源碼

protected DecorView generateDecor(int featureId) {

// 創(chuàng)建DecorView(FrameLayout)對象,ViewTree的根節(jié)點

return new DecorView(context, featureId, this, getAttributes());

}

下面是創(chuàng)建mContentParent的代碼

protected ViewGroup generateLayout(DecorView decor) {

// Apply data from current theme.

// 獲得window的樣式

TypedArray a = getWindowStyle();

/*省略掉一些設(shè)置樣式的代碼/

// 下面的代碼是給decorView填充孩子的

// 主要功能是根據(jù)不同的配置給decorView添加不同的布局文件(即給decorView添加不同的孩子節(jié)點)

int layoutResource;

int features = getLocalFeatures();

if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {

layoutResource = R.layout.screen_swipe_dismiss;

} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {

if (mIsFloating) {

TypedValue res = new TypedValue();

getContext().getTheme().resolveAttribute(

R.attr.dialogTitleIconsDecorLayout, res, true);

layoutResource = res.resourceId;

} else {

layoutResource = R.layout.screen_title_icons;

}

removeFeature(FEATURE_ACTION_BAR);

} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0

&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {

// Special case for a window with only a progress bar (and title).

// XXX Need to have a no-title version of embedded windows.

layoutResource = R.layout.screen_progress;

// System.out.println("Progress!");

} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {

// Special case for a window with a custom title.

// If the window is floating, we need a dialog layout

if (mIsFloating) {

TypedValue res = new TypedValue();

getContext().getTheme().resolveAttribute(

R.attr.dialogCustomTitleDecorLayout, res, true);

layoutResource = res.resourceId;

} else {

layoutResource = R.layout.screen_custom_title;

}

// XXX Remove this once action bar supports these features.

removeFeature(FEATURE_ACTION_BAR);

// 設(shè)置notitle的布局文件

} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {

// Dialog樣式的

if (mIsFloating) {

TypedValue res = new TypedValue();

getContext().getTheme().resolveAttribute(

R.attr.dialogTitleDecorLayout, res, true);

layoutResource = res.resourceId;

} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {

layoutResource = a.getResourceId(

R.styleable.Window_windowActionBarFullscreenDecorLayout,

R.layout.screen_action_bar);

} else {

layoutResource = R.layout.screen_title;

}

} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {

layoutResource = R.layout.screen_simple_overlay_action_mode;

} else {

// Embedded, so no decoration is needed.

layoutResource = R.layout.screen_simple;

// System.out.println("Simple!");

}

mDecor.startChanging();

// 下面的方法是將找到的不同的布局文件孽江,添加給decorView.

// 這里也說明了讶坯,我們經(jīng)常寫的requestWindowFeature(Window.FEATURE_NO_TITLE)代碼為什么一定放在setContentView之前。

// 因為系統(tǒng)會根據(jù)配置找不同的布局文件岗屏,而一旦添加了布局文件辆琅,就沒有辦法再移除title了。因此會拋出異常

mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

// 接下來是給賦值这刷,這里直接調(diào)用的findViewById()婉烟,其實內(nèi)部會調(diào)用decorView.findViewById();

ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

return contentParent;

}

generateLayout(DecorView decor) 主要完成了兩件事,1通過不同的配置給decorView添加不同layoutResource布局文件暇屋, 2找到id為IDANDROIDCONTENT的view似袁。

分析完setContentView代碼,我們發(fā)現(xiàn)setContentView.其實是將view添加到PhoneWindow的成員變量DecorView中的id為IDCONTENTANDROID的View節(jié)點上咐刨。還發(fā)現(xiàn)了DecorView的孩子節(jié)點會根據(jù)我們的requestWindowFeature()的不同昙衅,添加不同的layoutResource布局文件,而這些不同的layoutResource布局文件都是一個id為IDANDROIDCONTENT的孩子所宰。

接下來我們分析Diaog的show()方法

public void show() {

// 拿到PhoneWindow中的decorView對象

mDecor = mWindow.getDecorView();

// 產(chǎn)生布局參數(shù)

WindowManager.LayoutParams l = mWindow.getAttributes();

if ((l.softInputMode

& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {

WindowManager.LayoutParams nl = new WindowManager.LayoutParams();

nl.copyFrom(l);

nl.softInputMode |=

WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;

l = nl;

}

// wm添加decorView

mWindowManager.addView(mDecor, l);

}

我們發(fā)現(xiàn),寫到最后show()方法其實就是將decorView添加到wm中

而我們寫懸浮窗口的時候畜挥,直接用wm添加view仔粥。通過以上分析我們可以得出以下結(jié)論

結(jié)論

PhoneWindow的一個作用是給view包裹上一層DecorView。而DecorView中的布局結(jié)構(gòu)蟹但,會根據(jù)requestWindowFeature()的不同而不同(requestWindowFeature()方法躯泰,會影響DecorView的孩子節(jié)點(layoutResource布局文件))

我們的Activity和Dialog的布局都比較復(fù)雜,比如都可能有appbar(toolbar/actionbar)等华糖。因此通過PhoneWindow來封裝下可以更好的解耦代碼

PopupWindow或者Toast的布局比較簡單麦向。因此沒有必要包裹一層PhoneWindow。在源碼中也沒有發(fā)現(xiàn)有PhoneWindow的痕跡客叉。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诵竭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子兼搏,更是在濱河造成了極大的恐慌卵慰,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佛呻,死亡現(xiàn)場離奇詭異裳朋,居然都是意外死亡,警方通過查閱死者的電腦和手機吓著,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門鲤嫡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來送挑,“玉大人,你說我怎么就攤上這事暖眼√韪” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵罢荡,是天一觀的道長赡突。 經(jīng)常有香客問我,道長区赵,這世上最難降的妖魔是什么惭缰? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮笼才,結(jié)果婚禮上漱受,老公的妹妹穿的比我還像新娘。我一直安慰自己骡送,他們只是感情好昂羡,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著摔踱,像睡著了一般虐先。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上派敷,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天蛹批,我揣著相機與錄音,去河邊找鬼篮愉。 笑死腐芍,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的试躏。 我是一名探鬼主播猪勇,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼颠蕴!你這毒婦竟也來了泣刹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤犀被,失蹤者是張志新(化名)和其女友劉穎项玛,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弱判,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡襟沮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片开伏。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡膀跌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出固灵,到底是詐尸還是另有隱情捅伤,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布巫玻,位于F島的核電站丛忆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏仍秤。R本人自食惡果不足惜熄诡,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诗力。 院中可真熱鬧凰浮,春花似錦、人聲如沸苇本。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瓣窄。三九已至笛厦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間俺夕,已是汗流浹背裳凸。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留啥么,地道東北人登舞。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓贰逾,卻偏偏與公主長得像悬荣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子疙剑,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

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