我所理解的PhoneWindow的一個(gè)作用

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

android交流:364595326

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

我們今天要探討的是兩個(gè)問(wèn)題

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

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

我們從Dialog的setContentView()方法說(shuō)起。源碼

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,這個(gè)方法,其實(shí)就是給id為ID_ANDROID_CONTENT的view添加一個(gè)孩子

if (mContentParent == null) {

// 下面這個(gè)方法。完成了兩件事情

// 1 創(chuàng)建DecorView(FrameLayout),也就是我們經(jīng)常說(shuō)的window中有個(gè)DecorView對(duì)象。

// 2 給mContentParent賦值

installDecor();

} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

// 如果沒(méi)有5.0轉(zhuǎn)場(chǎng)動(dòng)畫,remove掉之前添加的所有view

mContentParent.removeAllViews();

}

if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

//? 5.0專場(chǎng)動(dòng)畫

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對(duì)象,之后將布局文件添加到mContentParent上面去

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

private void installDecor() {

mForceDecorInstall = false;

if (mDecor == null) {

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

mDecor = generateDecor(-1);

} else {

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

mDecor.setWindow(this);

}

if (mContentParent == null) {

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

mContentParent = generateLayout(mDecor);

}

}

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

下面是generateDecor(-1)源碼

protected DecorView generateDecor(int featureId) {

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

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é)點(diǎn))

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.

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

// 因?yàn)橄到y(tǒng)會(huì)根據(jù)配置找不同的布局文件,而一旦添加了布局文件,就沒(méi)有辦法再移除title了。因此會(huì)拋出異常

mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

// 接下來(lái)是給賦值,這里直接調(diào)用的findViewById(),其實(shí)內(nèi)部會(huì)調(diào)用decorView.findViewById();

ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

return contentParent;

}

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

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

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

public void show() {

// 拿到PhoneWindow中的decorView對(duì)象

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()方法其實(shí)就是將decorView添加到wm中

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

結(jié)論

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

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,578評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,701評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,691評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,974評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,694評(píng)論 6 413
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 56,026評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,193評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,719評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,668評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,846評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,255評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,592評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,394評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,635評(píng)論 2 380

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