android基础:Activity Window View ViewGroup

View与ViewGroup的关系

Android系统中的所有UI类都是建立在View和ViewGroup这两个类的基础上的。

  • 所有View的子类成为”Widget”
  • 所有ViewGroup的子类成为”Layout”
  • ViewGroup是一种特殊的View

View和ViewGroup之间采用了组合设计模式,可以使得“部分-整体”同等对待。ViewGroup作为布局容器类的最上层,布局容器里面又可以有View和ViewGroup

如下图

区别

  • 如果viewgroup有一个子view是invisible状态,viewgroup就是invisible状态


Activity与window

Activity

在Activity中使用LayoutInflater。
LayoutInflater是一个用来实例化XML布局文件为View对象的类
LayoutInflater.infalte(R.layout.test,null)用来从指定的XML资源中填充一个新的View

  • Activity的作用相当于人机交互界面,负责管理跟维护View与手机的操作。比如提供用户处理事件的API,如onKeyEvent, onTouchEvent等。

Window

  • window是一个抽象类
  • 当我们调用Acitivity的 setContentView方法的时候实际上是调用的Window对象的setContentView方法,Activity中关于界 面的绘制实际上全是交给Window对象来做的

Activity与Window关系

一个Activity包含了一个Window,Window才是真正代表一个窗口,也就是说Activity可以没有Window,那就相当于是Service了。在ActivityThread中也有控制Service的相关函数或许正好印证了这一点。
 Activity和Window的第一次邂逅是在ActivityThread调用Activity的attach()函数时。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

//[window]:通过PolicyManager创建window,实现callback函数,所以,当window接收到
//外界状态改变时,会调用activity的方法,

final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
....
mWindow = PolicyManager.makeNewWindow(this);
//当window接收系统发送给它的IO输入事件时,例如键盘和触摸屏事件,就可以转发给相应的Activity
mWindow.setCallback(this);
.....
//设置本地窗口管理器
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
.....
}

 在attach()中,新建一个Window实例作为自己的成员变量,它的类型为PhoneWindow,这是抽象类Window的一个子类。然后设置mWindow的WindowManager。

Window,Activity和DecorView

DecorView是FrameLayout的子类,它可以被认为是Android视图树的根节点视图。DecorView作为顶级View,一般情况下它内部包含一个竖直方向的LinearLayout,在这个LinearLayout里面有上下两个部分(具体情况和Android版本及主体有关),上面的是标题栏,下面的是内容栏。在Activity中通过setContentView所设置的布局文件其实就是被加到内容栏之中的,而内容栏的id是content,在代码中可以通过ViewGroup content = (ViewGroup)findViewById(R.android.id.content)来得到content对应的layout。
 Window中有几个视图相关的比较重要的成员变量如下所示:

  • mDecor:DecorView的实例,标示Window内部的顶级视图
  • mContentParent:setContetView所设置的布局文件就加到这个视图中
  • mContentRoot:是DecorView的唯一子视图,内部包含mContentParent,标题栏和状态栏。

    Activity中不仅持有一个Window实例,还有一个类型为View的mDecor实例。这个实例和Window中的mDecor实例有什么关系呢?它又是什么时候被创建的呢?
     二者其实指向同一个对象,这个对象是在Activity调用setContentView时创建的。我们都知道Activity的setContentView实际上是调用了Window的setContentView方法。
1
2
3
4
5
6
7
8
9
10
11
12
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) { //[window]如何没有DecorView,那么就新建一个
installDecor(); //[window]
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
....
//[window]第二步,将layout添加到mContentParent
mLayoutInflater.inflate(layoutResID, mContentParent);
.....
}

参考文献

Android视图架构详解

Android应用程序窗口(Activity)的视图对象(View)的创建过程分析