一、简述如何将Activity展现在手机上
Tips:
Activity本身是没办法处理显示什么控件(view)的,是通过PhoneWindow进行显示的
换句话说:activity就是在造PhoneWindow,显示的那些view都交给了PhoneWindow处理显示
1、在Activity创建时调用attach方法:
2、attach方法中会调用PolicyManager.makeNewWindow()
实际工作的是IPolicy接口的makeNewWindow方法
①、其中创建了一个window(可以比喻为一个房子上造了一个窗户):mWindow = PolicyManager.makeNewWindow(this);
②、在window这个类中,才调用了setContentView(),这是最终的调用
在Activity的setContentView方法中,实际上是调用:getWindow().setContentView(view, params);
这里的getWindow()就是获取到一个Window对象
Tips:
为啥attch优先于onCreate调用,就是由于在attch方法中,会创建window,有了window才能调用setContentView
3、在IPolicy的实现类中创建了PhoneWindow:
①、由mWindow = PolicyManager.makeNewWindow(this);,
②、这里的makeNewWindow(this);方法中,返回的是:return sPolicy.makeNewWindow(context);
③、这个sPolicy实际是一个接口,其实现类是Policy,其中只是创建了一个PhoneWindow
4、在PhoneWindow的setContentView中向ViewGroup(root)中添加了需要显示的内容
①、PhoneWindow是继承Window的
②、setContentView这个方法中,需要先判断一个mContentParent是否为空,因为在默认进来的时候,什么都没创建呢
此时需要创建:installDecor(),DecorView是最根上的显示的
可以通过adt中的的tools中有个hierarchyviewer.bat的工具,可以查看手机的结构
③、DecorView:是继承与FrameLayout的,作为parent存在,最初显示的
④、下次再加载的时候,mContentParent就不为空了,会将其中的所有的view移除掉,然后在通过布局填充器加载布局
二、三者关系:
1、在Activity中调用attach,创建了一个Window
2、创建的window是其子类PhoneWindow,在attach中创建PhoneWindow
3、在Activity中调用setContentView(R.layout.xxx)
4、其中实际上是调用的getWindow().setContentView()
5、调用PhoneWindow中的setContentView方法
6、创建ParentView:
作为ViewGroup的子类,实际是创建的DecorView(作为FramLayout的子类)
7、将指定的R.layout.xxx进行填充
通过布局填充器进行填充【其中的parent指的就是DecorView】
8、调用到ViewGroup
9、调用ViewGroup的removeAllView(),先将所有的view移除掉
10、添加新的view:addView()
Tips:
①、Activity就是在造“窗户”,即创建PhoneWindow
②、PhoneWindow才是进行显示view的操作,主要就是setContentView()
setContentView整个过程主要是如何把Activity的布局文件或者java的View添加至窗口里,重点概括为:
创建一个DecorView的对象mDecor,该mDecor对象将作为整个应用窗口的根视图。
依据Feature等style theme创建不同的窗口修饰布局文件,并且通过findViewById获取Activity布局文件该存放的地方(窗口修饰布局文件中id为content的FrameLayout)。
将Activity的布局文件添加至id为content的FrameLayout内。
当setContentView设置显示OK以后会回调Activity的onContentChanged方法。Activity的各种View的findViewById()方法等都可以放到该方法中,系统会帮忙回调。
LayoutInflater的使用中重点关注inflate方法的参数含义:
inflate(xmlId, null); 只创建temp的View,然后直接返回temp。
inflate(xmlId, parent); 创建temp的View,然后执行root.addView(temp, params);最后返回root。
inflate(xmlId, parent, false); 创建temp的View,然后执行temp.setLayoutParams(params);然后再返回temp。
inflate(xmlId, parent, true); 创建temp的View,然后执行root.addView(temp, params);最后返回root。
inflate(xmlId, null, false); 只创建temp的View,然后直接返回temp。
inflate(xmlId, null, true); 只创建temp的View,然后直接返回temp。
1,如何理解Activity,View,Window三者之间的关系?
这个问题真的很不好回答。所以这里先来个算是比较恰当的比喻来形容下它们的关系吧。Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图)LayoutInflater像剪刀,Xml配置像窗花图纸。
1:Activity构造的时候会初始化一个Window,准确的说是PhoneWindow。
2:这个PhoneWindow有一个“ViewRoot”,这个“ViewRoot”是一个View或者说ViewGroup,是最初始的根视图。
3:“ViewRoot”通过addView方法来一个个的添加View。比如TextView,Button等
4:这些View的事件监听,是由WindowManagerService来接受消息,并且回调Activity函数。比如onClickListener,onKeyDown等。