我所理解的PhoneWindow的一个作用

转载自blog.csdn.net/u013356254/article/details/55116259

android交流:364595326

android中我们常见的Activity,Diaog等内部都封装了PhoneWindow对象。

我们今天要探讨的是两个问题

为什么系统在创建Acivity或者Dialog的时候封装了PhoneWindow对象,而我们自己写悬浮窗口的时候并没有使用PhoneWindow对象?

为什么Diaog封装了PhoneWindow对象,而PopupWindow却直接将contentView封装成PopupDecorView(FrameLayout子类),直接调用WM来添加view?

我们从Dialog的setContentView()方法说起。源码

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

// 调用的是window的方法

mWindow.setContentView(view, params);

}

下面是PhoneWindow的setContentView()方法。

@Override

public void setContentView(int layoutResID ) {

// mContentParent是id为ID_ANDROID_CONTENT的FrameLayout

// 我们经常写的setContentView,这个方法,其实就是给id为ID_ANDROID_CONTENT的view添加一个孩子

if (mContentParent == null) {

// 下面这个方法。完成了两件事情

// 1 创建DecorView(FrameLayout),也就是我们经常说的window中有个DecorView对象。

// 2 给mContentParent赋值

installDecor();

} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

// 如果没有5.0转场动画,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) {

// 产生decorView 也就是ViewTree的根节点

mDecor = generateDecor(-1);

} else {

// 将decorView和window关联起来

mDecor.setWindow(this);

}

if (mContentParent == null) {

// 根据decorview产生我们的ContentParent也就是id为content的viewGroup,

mContentParent = generateLayout(mDecor);

}

}

我们可以看到installDecor()方法主要是创建了DecorView,和mContentParent对象。

下面是generateDecor(-1)源码

protected DecorView generateDecor(int featureId) {

// 创建DecorView(FrameLayout)对象,ViewTree的根节点

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

}

下面是创建mContentParent的代码

protected ViewGroup generateLayout(DecorView decor) {

// Apply data from current theme.

// 获得window的样式

TypedArray a = getWindowStyle();

/*省略掉一些设置样式的代码/

// 下面的代码是给decorView填充孩子的

// 主要功能是根据不同的配置给decorView添加不同的布局文件(即给decorView添加不同的孩子节点)

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);

// 设置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.

// 这里也说明了,我们经常写的requestWindowFeature(Window.FEATURE_NO_TITLE)代码为什么一定放在setContentView之前。

// 因为系统会根据配置找不同的布局文件,而一旦添加了布局文件,就没有办法再移除title了。因此会抛出异常

mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

// 接下来是给赋值,这里直接调用的findViewById(),其实内部会调用decorView.findViewById();

ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

return contentParent;

}

generateLayout(DecorView decor) 主要完成了两件事,1通过不同的配置给decorView添加不同layoutResource布局文件, 2找到id为IDANDROIDCONTENT的view。

分析完setContentView代码,我们发现setContentView.其实是将view添加到PhoneWindow的成员变量DecorView中的id为IDCONTENTANDROID的View节点上。还发现了DecorView的孩子节点会根据我们的requestWindowFeature()的不同,添加不同的layoutResource布局文件,而这些不同的layoutResource布局文件都是一个id为IDANDROIDCONTENT的孩子。

接下来我们分析Diaog的show()方法

public void show() {

// 拿到PhoneWindow中的decorView对象

mDecor = mWindow.getDecorView();

// 产生布局参数

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);

}

我们发现,写到最后show()方法其实就是将decorView添加到wm中

而我们写悬浮窗口的时候,直接用wm添加view。通过以上分析我们可以得出以下结论

结论

PhoneWindow的一个作用是给view包裹上一层DecorView。而DecorView中的布局结构,会根据requestWindowFeature()的不同而不同(requestWindowFeature()方法,会影响DecorView的孩子节点(layoutResource布局文件))

我们的Activity和Dialog的布局都比较复杂,比如都可能有appbar(toolbar/actionbar)等。因此通过PhoneWindow来封装下可以更好的解耦代码

PopupWindow或者Toast的布局比较简单。因此没有必要包裹一层PhoneWindow。在源码中也没有发现有PhoneWindow的痕迹。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容