Activity Window View-[Android_YangKe]

转载请注明 Android_YangKe,谢谢!

老实说自己做 Android 有一段时间了,但发现 Android 技能提升上有了点小瓶颈,总感觉自己什么都会,又都感觉自己什么都不会,于是就有了此片文章。

下面我们将通过 Window 慢慢引出三者之间的关系,同时适当的源码辅助分析。说到源码相信很多人都是心中都一万个 mmb,劳资这么差的英文,动不动成千上万行的代码,脑袋瞬间短路好不好... 微笑-微笑 。

Activity,View 是什么我相信不用解释,而 Window 在使用频率上相对来说就低了些,那么 Window 是什么?在 Android 体系中扮演着什么样的角色?下面是 Google 工程师对 Window 类的一些介绍,我们来看下。

//Window.java
/**
 * Abstract base class for a top-level window look and behavior policy.  An
 * instance of this class should be used as the top-level view added to the
 * window manager. It provides standard UI policies such as a background, title
 * area, default key processing, etc.
 *
 * <p>The only existing implementation of this abstract class is
 * android.view.PhoneWindow, which you should instantiate when needing a
 * Window.
 */

大致意思:Window 是一个基础类,是顶级视图的承载。提供了标准的 UI 策略,如背景,标题。同时 Window 只有一个实现类PhoneWindow。官方的解释还是比较给力,很详细的介绍了该对象,现在我们对 Window 有了一个初步认识。下面我们将结合具体案例进行探索。

Activity 中 onCreate 函数相信大家再熟悉不过了,如我们将里面的setContentView函数注释掉时,会发现原来我们的炫酷的页面只留下一个标题加空白页面(前提我们没有修改默认的主题),这么看来此行代码很关键。

//Activity.java
public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

一般来说我们的 Activity 都是继承自 AppCompatActivity,但最终的顶层父类是 Activity。通过上面源码我们可以发现 Activity 只是 View 宿主,并没有真正的实现setContentView而是通过 getWindow 操作此函数,我们来看下 getWindow。

//Activity.java
public Window getWindow() {
    return mWindow;
}
final void attach(...) {
    attachBaseContext(context);
    mWindow = new PhoneWindow(this, window,activityConfigCallback);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    ...
}

很简单 getWindow 函数返回了一个实例PhoneWindow。由于代码中没有对 getWindow 判空,我们可以推测出 attach 函数一定在 setContentView 之前执行,也就是 onCreate 函数之前,不然一定会报NullPointerException

扯得有点多,言归正传。这里我们看到了 Window 的身影,从上文我们了解到 Window 是顶级视图的承载,而PhoneWindow又是 Window 的唯一子类,我们尝试着去 PhoneWindow中探索 setContentView

//PhoneWindow.java

// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;

public void setContentView(View view, ViewGroup.LayoutParams params) {
    if (mContentParent == null) {
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }
    ...
}

一大串代码(当然我省略了一部分代码)果不其然,真正的操作的就是在 Window 的 setContentView函数中完成的,首先。

  • mDecor:Window 上最顶层的视图,如果按照从上到下的顺序,分别是状态栏,标题栏,具体 View 控件。由于其继承了 FrameLayout 也就是说 mDecor 也是一个 ViewGroup。
  • mContentParent:表示视图区域,里面可以是 mDecor,也可以是 mDecor 中的具体 View,但不代表具体视图。

了解了这两个对象的作用,我们继续看代码。removeAllViews函数顾名思义,也就是从当前 Window 中移除所有 View,这里就不进入源码进行分析了(代码水很深,随时保留精气神)。现在就剩下installDecor了,此函数貌似很关键,我们跟进来看下。

//PhoneWindow.java
private void installDecor() {
    if (mDecor == null) {
        mDecor = generateDecor(-1);
        ...
    } else {
        mDecor.setWindow(this);
    }
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);
    ...
    }
}

首先映入眼帘的是generateDecor,同时此函数的返回值赋予了 mDecor。随后系统调用了generateLayoutgenerateLayout从字面意义上来看是初始化布局,莫非跟布局 View 有关,我们来看一下。

//PhoneWindow.java
protected ViewGroup generateLayout(DecorView decor) {
 // Apply data from current theme.
 TypedArray a = getWindowStyle();
 if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
     requestFeature(FEATURE_NO_TITLE);
 } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
     // Don't allow an action bar if there is no title.
     requestFeature(FEATURE_ACTION_BAR);
 }
 if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
     setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
 }
 ...
}      

这里我们抛去 if 的各种判断直接看这几个常量:FLAG_FULLSCREENFEATURE_NO_TITLEFLAG_FULLSCREEN等等,是不是似曾相识呢?相信大家在 onCreate 函数setContentView前都有过重设当前 Activity 样式的经历,严格来说应该是 Window (Activity 全屏、去除标题栏)。也就是说屏幕上页面的尺寸,样式都是通过 Window 来控制的!看来此函数很重要,打起精神,我们再来分析一波。

//PhoneWindow.java
protected ViewGroup generateLayout(DecorView decor) {
    // Remaining setup -- of background and title -- that only applies
    // to top-level windows.

    WindowManager.LayoutParams params = getAttributes();
    if (!hasSoftInputMode()) {
        params.softInputMode = a.getInt(R.styleable.Window_windowSoftInputMode, params.softInputMode);
    }
    if (params.windowAnimations == 0) {
        params.windowAnimations = a.getResourceId(R.styleable.Window_windowAnimationStyle, 0);
    }
    ...
    if (getContainer() == null) {
        final Drawable background;
        if (mBackgroundResource != 0) {
            background = getContext().getDrawable(mBackgroundResource);
        } else {
            background = mBackgroundDrawable;
        }
        mDecor.setWindowBackground(background);

        final Drawable frame;
        if (mFrameResource != 0) {
            frame = getContext().getDrawable(mFrameResource);
        } else {
            frame = null;
        }
        mDecor.setWindowFrame(frame);
        ...
        if (mTitle != null) {setTitle(mTitle);}
        if (mTitleColor == 0) {mTitleColor = mTextColor;}
        setTitleColor(mTitleColor);
    }
    mDecor.finishChanging();

    return contentParent;
}

首先我们看下官方给的注释:

  • Remaining setup -- of background and title -- that only applies to top-level windows.

将自己置身于情境之中,大概意思:设置标题,背景颜色,将视图应用在顶层 View 上,谁呢?DecorView。

其次:
获取 Window 的一些属性,并根据情况对输入法模式、载入动画等等进行配置。

最后:
对 Window 承载的视图进行背景设置,边距设置,标题栏颜色设置,标题栏设置等等。

到这里相信你对 Window 的作用,以及其在 Android 中扮演着怎样的角色有了一定的认知。下面我们来看一张图片,辅助我们理解 Activity、Window、View 之间的关系:(图片源自互联网,出处不明)

yangke.png

最外层是 Activity、其次是 PhoneWindow、最后是我们常操作的 View 控件。通过这张图相信你对 Activity、Window、View 有了进一步的认识,下面我们再来重新认识下三者。

View:说到 View 相信大家都很熟悉,像什么 TextView、Button、ImageView 等等我相信你可以一口气说一大堆。View 是具体视图的最小展示单元。在页面上可以是一张图片,一段文本,一个网页。简而言之:View 就是具体视图(常常与用户打交道)。

Window:我们真正意义上所说的页面,是 Activity 任命的大使,主要用于管理 View,设置窗口(视图)样式、尺寸、输入法模式等。我们也可以通过WindowManager对 View 进行添加和移除操作等。简而言之:Window 主要用于控制显示窗口的尺寸、样式、View 的移除添加(常常与研发人员打交道)。

Activity:页面的载体。维护应用程序的生命周期、提供用户处理事件的 API、进程间通信等。简而言之:用于管理系统组件相关事物。

整理:
Activity-> PhoneWindow-> DecorView。

总结:
Activity 作为四大组件主要与系统进行交互,用于组件间通信,生命周期管理、进程通信等。Window 作为视图载体,主要用于管理视图的尺寸、样式、输入法模式、View 的移除添加等,需要依托于 Activiity。View 就比较简单了,不同的 View 用于展示不同的视图,例:文本组件,图片组件,甚至网页等,需要依托于 Window。也就是说三者相辅相成,谁离开都将无存在意义。

尾声:
为什么 View 不直接与 Activity 关联呢?反而又设计出一个 Window 对象?

其实这里有些面向对象的概念,也就是说对于庞大的功能我们需要进行拆分,让其尽量独立,各司其职,同时在功能互不影响的情况下,相辅相成。

完~

喜欢有帮助的话: 双击、评论、转发,动一动你的小手让更多的人知道!

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

推荐阅读更多精彩内容