最近一直在研究View
的绘制相关的机制,发现需要补充一下Android View Architecture的相关知识,所以就特地研究了一下这方面的代码,写成本篇文章
为了节约你的时间,本篇文章内容大致如下:
Activity
,DecorView
,PhoneWindow
和ViewRoot
的作用和相关关系
Android View Architecture
先来几张图,大致展现一下Android 视图架构的大概。
感谢网友提醒,泛化和实现这两种关系的箭头画反啦。以后要仔细学一遍UML了,平时经常画,如果有错误可真是闹笑话啊。
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 |
//[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); ..... } |
代码很清楚的显示了布局文件的视图是添加到mContentParent
中,而且Window
通过installDecor
来新建DecorView
。