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.
 *
 * 

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 之间的关系:(图片源自互联网,出处不明)

Activity Window View-[Android_YangKe]_第1张图片
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 对象?

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

完~

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

你可能感兴趣的:(Activity Window View-[Android_YangKe])