结合源码,探索Android中的Window与DecorView

用心分享,你的 点赞|转发分享 是对我最大的鼓励,关注以及时获取最新推文。

Android中View可以说是最为重要的几个地方之一,包括事件分发,测量,绘制等等,都是非常常见的情况。那么我们要想好好掌握这些知识,就得深入了解Andorid整个View从开始到完成所经历的一系列工作。

本文分析的源代码均来自Android API 24。

1. Activity 和 Window

在Android中,Activity并不负责视图控制,它只是控制生命周期和处理事件,真正控制视图的是Window。一个Activity包含了一个Window,Window才是真正代表一个窗口,也就是说Activity可以没有Window,那就和Service没多大差别了。

Window第一次出现在Activity中是在ActivityThread调用Activity的attach()方法时,通过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, NonConfigurationInstanceslastNonConfigurationInstances, Configuration config, String referrer,IVoiceInteractor voiceInteractor) { //.... //在这里直接new一个Window mWindow = PolicyManager.makeNewWindow(this);//设置回调接口,当window接收系统发送给它的例如键盘和触摸屏事件,就可以通知Activity,Activity做出相应的处理 mWindow.setCallback(this); ..... //设置窗口管理器 mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); ..... }

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

2. DecorView

首先简单介绍一下DecorView,这里引用任玉刚大神的《Android开发艺术探索》书中的介绍:

它是一个顶级View,内部会包含一个竖直方向的LinearLayout,这个LinearLayout有上下两部分,分为titlebar和contentParent两个子元素,contentParent的id是content,而我们自定义的Activity的布局就是contentParent里面的一个子元素。View层的所有事件都要先经过DecorView后才传递给我们的View。

那么DecorView是何时出现的呢??又是如何和window产生联系呢??

《结合源码,探索Android中的Window与DecorView》

首先,如上图我们可以看到Activity中包含了 Window、DecorView、WindowManager 等成员变量,那么我们就从Activity的创建过程中去逐步寻找它们。

首先在Activity中的onCreate方法中我们都会写一句setContentView的方法调用,将我们自定义的Activity布局传入。那么我们跟进该方法去看一下具体实现。

《结合源码,探索Android中的Window与DecorView》

通过getWindow来获取成员变量mWindow。

《结合源码,探索Android中的Window与DecorView》

然后调用window的setContentView()方法。该方法来进行我们Activity的布局设置。然后又接着调用了initWindowDecorActionBar()方法来进行对ActionBar的新建和初始化。我们暂时不管该方法。

mWindow类型是Window,是一个接口,而在安卓中实现Window接口的实现类只有PhoneWindow,所以进入PhoneWindow查看setContentView()方法的具体实现。先上源代码:

《结合源码,探索Android中的Window与DecorView》

首先会在上图标记1处判断mContentParent是否为空,如果为空,会执行installDecor()方法,那么mContentParent是什么呢?

《结合源码,探索Android中的Window与DecorView》

通过定义可以看出,mContentParent是一个ViewGroup类型的变量,它是Activity的一个成员变量。我们所写的setContetView()所设置的布局文件就加到这个视图中。根据官方解释它可能是mDecor自身,也可能是mDecor的子View。

继续回到setContentView中看代码,如果mContentParent为空,那么会执行installDecor()方法,跟进这个方法,顾名思义,新建DecorView。下面给出源代码:

《结合源码,探索Android中的Window与DecorView》

在installDecor方法中标注1处,如果mDecor为空(mDecor是Window持有的一个成员变量,指的就是DecorView),那么在 generateDecor()中去实例化新建DecorView,我们继续跟进generateDecor()查看源代码:

《结合源码,探索Android中的Window与DecorView》

在这里前面一段代码都是初始化所需要的context,最后返回一个实例化的DecorView()。在DecorView构造方法中进行初始化工作。

《结合源码,探索Android中的Window与DecorView》

上图是DecorView的一些初始化工作,就不再展开,有兴趣的同志们可以研究。

返回到installDecor()方法中继续往下,到标记处2,会判断mContentParent是否为空,如果为空,通过 generateLayout()来将我们具体的布局加载到DecorView中。跟入 generateLayout()方法查看源代码(由于方法中代码过长不便于截图,我贴出关键代码):

...//代码前面都是在获取主题相关 //在这个方法里将mContentParent的布局转换并添加到DecorVew中 //具体代码在下一个代码框中 mDecor.onResourcesLoaded(mLayoutInflater,layoutResource); //contentParent就是root的父布局。 ViewGroup contentParent =(ViewGroup)findViewById(ID_ANDROID_CONTENT); return contentParent;
//将mContentParent布局转换为View final View root = inflater.inflate(layoutResource,null); //将mContentParent加入到DecorView中 mDecor.addView(root,newViewGroup.MarginLayoutParams(MATCH_PARENT,MATCH_PARENT)); //mContentRoot就是mContentParent视图 mContentRoot = (ViewGroup)root; 

至此generateLayout()方法分析完毕,返回contentParent变量,赋值给mContentParent成员变量。

随后上述步骤也是installDecor()方法的主要代码,因此继续返回到setContentView方法继续查看(把setContentView的图继续贴下来避免返回去翻图):

《结合源码,探索Android中的Window与DecorView》

图中标注处2的代码,则是将我们的自定义布局加入到mContentParent(也就是id为R.id.content)布局中。最后标记处3则是通过回调来通知ActivityContent已经发生了变化,由Activity来做出相应的处理。

3. DecorView 和 Window

至此已经setContentView已经完成,DecorView也已经新建,我们自定义布局也加入到mContentParent布局中,但是此时mDecorView还没有被WindowManager正式添加到Window中。因此Window此时还无法接受外界的信息,也无法提供具体的功能。

所以在activity中的onResume()方法中调用了makeVisible()方法来进行添加,同时也是把Window加入到WindowManager中

 void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); //获得WindowManager(WindowManager extends ViewManager) wm.addView(mDecor, getWindow().getAttributes()); //将DecorView加入到Window中 mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE); } 

至此整个decorView的加载过程和Activity的Window创建过程已经完成,Decor将会 显示出来呈现在手机屏幕上。

原文:初探Android中Window与DecorView

签约作者:晨心w

END

1. 关注并回复 [加群], 邀请你进Android技术群

2. 公众号开放投稿:

你有好的文章,我有平台,那么~ 《结合源码,探索Android中的Window与DecorView》 戳我投稿

一位6年软件工程师的总结与反思

iOS 用户赞赏通道 [请备注姓名]

《结合源码,探索Android中的Window与DecorView》

一个 有价值、有温度 的公众号

一位 爱分享、乐助人 的开发者

期待你的关注并一起交流

    原文作者:Android源码分析
    原文地址: https://juejin.im/entry/599a2cd56fb9a0249716dc75
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞