关于Android View体系里面的相关知识,可能会比较乱,先都罗列出来再说,后期再做整理。
自己做的笔记,不太适合学习用,大家看看就好,有问题烦请指正。
几个常用对象之间的关系
Activity  间接继承自  Context
activity.getWindow  获取到的是  PhoneWindow,继承自 Window(抽象类) 
PhoneWIndow中持有mDecor① 和 mContentParent②:
①:mDecor = new DecorView(),间接继承ViewGroup DecorView extends FrameLayout extends ViewGroup 
②:mContentParent = generateLayout(mDecor);
 `protected ViewGroup generateLayout(DecorView decor)`
 `mContentParent `是`ViewGroup`对象
setContentView的执行
getWindow().setContentView(resID),其中window对象在Activity的attach()方法中初始化 (PhoneWindow)PhoneWindow.setCOntentView()源码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
//阳氏翻译:在insatllDecor()过程中可能会设置FEATURE_CONTENT_TRANSITIONS的值,直到theme属性明确
if (mContentParent == null) {
installDecor();//这里面new了mDecor和mContentParent俩对象
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);//布局加载到mContentParent中去
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}关注后两个注释即可,一个初始化了
Decor和ContentParent;一个加载了布局。installDecor()中有这两句:①:mDecor = generateDecor();②:`mContentParent = generateLayout(mDecor);`大致如图:

事件分发机制
白话
依上图可见,手指触摸屏幕瞬间会触发Activity.dispatchTouchEvent,依次传递到window、decor直到ViewGroup.dispatchTouchEvent()方法中来。
跟着,ViewGroup的dispatchTouchEvent方法中一堆逻辑判断,判断是否拦截。
如果拦截,跳转到ViewGroup.onTouchEvent();
如果不拦截,则遍历child,执行child.dispatchTouchEvent()方法;
    child是view的话,在 `view.dispatchTouchEvent()`方法中先判断有无 `touchListener`,
            有的话执行`touchLIstener`,否则  执行 `view.onTouchEvent()`方法
代码可抽象成这样:
1  | //不是源码!!!!!  | 
后续: view.onTouchEvent()中,若view的clickable或LongClickable为true  且  ACTION_UP ,则调用 performClick()方法;
        `performClick()`方法中对`onCLickListener` 进行了响应:`mListenerInfo.mOnClickListener.onClick(this)`
图示

对了,默认情况下ViewGroup.onInterceptTouchEvent()返回false,即默认可以一条路走下来。
View的工作流程
当我们调用Activity的startActivity()方法时,最终是调用ActivityThread.handleLaunchActivity方法 来创建Activity的。
1  | public Activity handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {  | 
1  | final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {  | 
可以看出handleResumeActivity中最终是把布局委托给了WindowManager去创建。
WindowManager是一个接口,主要实现是在WindowManagerImpl中:
1  | 
  | 
跟着又用到了mGlobal.addView()方法,mGlobal是windowManagerGlobal对象,windowManagerGlobal中addView方法如下:
1  | public void addView(View view, ViewGroup.LayoutParams params,  | 
②中的root即ViewRootImpl,ViewRootImpl还有一个方法 PerformTraversals()。这个方法使得ViewTree开始View的工作流程。performMeasure、performLayout、performDraw方法都在里面。对应measure、layout、draw方法。
提一句,里面的performMeasure()会传入两个参数 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
MeasureSpec的最顶层
PerformTraversals中,有如下代码:
1  | if(!mStopped){  | 
MeasureSpec是一个32位的int值,前两位表示mode,后30位代表size。这个应该要展开来讲,不清楚的可以网上看看。
这里的performMeasure中传入的两个值就是最顶层的MeasureSpec。由 getRootMeasureSpec()方法获取:
1  | private static int getRootMeasureSpec(int windowSize, int rootDimension) {  | 
windowSize是窗口的尺寸,(1920*1080或者是2660**1440等,根据设备而定);
然后根据LayoutParams具体是什么来设置measureSpec。代码写的很清楚。
再往下走,看performMeasure()方法:
1  | private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {  | 
关键就那一句,熟悉的measure方法开始了。
不要忘了mView是谁,没错,就是上文(ViewRootImpl.setView())中传来的view,上上文(windowManager.addView())中传来的view——mDecor。
如果你记忆力还比较好的话,你应该记得文章开头的地方列出了decor的继承关系——继承自ViewGroup。





