前言:不断反思,不断进步,不断学习!
不知怎么的,觉得自己的语言组织不起来,逻辑性不强,所以就多学学别人的风格,背诵。
View的展示是从Activity的setContentView方法开始,以此为入口,以Android6.0为source-code,分析看看。
1、
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback, WindowControllerCallback {
...
/**
* Set the activity content from a layout resource. The resource will be
* inflated, adding all top-level views to the activity.
*
* @param layoutResID Resource ID to be inflated.
*
* @see #setContentView(android.view.View)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
*/
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
...
}
添加所有的topview到Activity, getWindow().setContentView(layoutResID)是怎么实现的呢?是Window.java的一个抽象方法
2、
public abstract void setContentView(View view);
最终的实现类是会进入的PhoneWindow.java的setContentView方法 ,有很多setContentView的重载。
3、
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mContentParent.addView(view, params);
....
}
mContentParent是一个ViewGroup对象,也是Activity内容部分的根View,他的创建依赖installDecor()
4、
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
......
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
......
}
installDecor在创建DecorView(顶级View,是FrameLayout的子类,是整个Activity的框架)的同时,然后通过generateLayout(mDecor)来创建ViewGroup mContentParent ,与其说是创建,不如说是获取,是从顶级View实例化的xml布局中获取生成的。
5、
protected ViewGroup generateLayout(DecorView decor) {
.......
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
.......
return contentParent;
}
回到4中,将我们需要加入的view加入到contentParent,这样我们要展示的View就准备好了,但是还没有开始绘制。
之后,随着Activity的onCreate方法执行完毕,view加载结束后,AMS会调用ActivityThread.handleResumeActivity方法
6、
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
boolean reallyResume) {
.......
ActivityClientRecord r = performResumeActivity(token, clearHide);
.......
final Activity a = r.activity; //获取activity对象
.......
decor.setVisibility(View.INVISIBLE); //显示decor
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l); //加载了我们的View
}
.......
}
这里最重要的代码就是wm.addView(decor, l);但是这里要先说一下wm,看上述代码可知只是一个ViewManager类型,实际上是一个WindowManager(实现了ViewManager接口)。他通过activity的getWindowManager()获得,获得的WindowManager对象最初来自于Window类的getWindowManager()方法,由setWindowManager()创建。
7、
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
.......
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
这里可以看到,首先我们通过mContext对象获取系统的WindowManagerService。然后通过createLocalWindowManager方法复制了一份。所以说对于WindowManagerService对象,每一个Activity程序都会有一个自己的mWindowManager,回到 wm.addView(decor, l)方法
这个方法的实现在WindowManagerImpl里面,发现他只是一个代理,这个方法最终交给了WindowManagerGlobal类的一个单例来执行。
8、
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); //单例对象
...............
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
...............
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
.........
ViewRootImpl root;
.........
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
.........
root.setView(view, wparams, panelParentView);//后续会关注于ViewRoot的实现
.........
}
}
这里我们首次看到了ViewRoot,这是非常重要的类。在ViewRoot的构造函数中可见,
9、
/**
* The top of a view hierarchy, implementing the needed protocol between View
* and the WindowManager. This is for the most part an internal implementation
* detail of {@link WindowManagerGlobal}.
*
public ViewRootImpl(Context context, Display display) {
.......
mWindowSession = WindowManagerGlobal.getWindowSession();
......
}
Session是在WMS中直接创建的,如名字一样,这是一个WMS与ViewRoot的一个会话,由此ViewRoot的功能就非常清楚:是View与WMS通信的桥梁,在ViewRoot中使用WMS。我们了解了ViewRoot的功能,让我们看看他是如何执行的。我们回到WindowManagerImpl的addView()。ViewRoot使用setView方法将我们需要显示View放入ViewRoot内进行操作。
10、
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
..........
requestLayout();
..........
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel);
.........
}
我靠,才知道自定义控件使用到的requestLayout、invalidate都是这个类的,有必要好好研究一下。都是和绘制相关的,这里还是先关注于之前的准备工作
11、
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets,
InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outInputChannel);
}
这里代理调用了mService的addWindow()方法,其中传入的参数window是ViewRoot内的一个内部类通过binder机制放入到WMS中用于WMS反向调用ViewRoot,即与Session相反。这样ViewRoot与WMS建立了双向链接。这时,WMS看看addWindow()方法最终会调用到Session的一个方法
12、
void windowAddedLocked() {
........
mSurfaceSession = new SurfaceSession();
........
mService.mSessions.add(this);
}
最终SurfaceSession被放入了Service的HashSet集合里面,
,SurfaceSession就是WMS与SurfaceFlinger的通信桥梁,SurfaceFlinger是用来绘制surface的一个服务,至此Activity的启动消息被执行完成,但是我们还是没有获取到画布,进入performTraversals()方法,有这段代码
13、
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
14、实现:
// These can be accessed by any thread, must be protected with a lock.
// Surface can never be reassigned or cleared (use Surface.clear()).
......
int relayoutResult = mWindowSession.relayout(
mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
mSurface);
就是讲mSurface传入了Session的方法中。mSurface是ViewRoot自己建立的一个Surface对象,但是是个空构造函数没什么意义。这里传入Session就是要利用WMS充实这个Surface对象,这个Surface就是我们要绘制的屏幕。在Session中,他直接把Surface对象传入了mService即WMS对象中。
15、
public int relayout(IWindow window, ..., Surface outSurface) {
......
int res = mService.relayoutWindow(this, window, ..., outSurface);
....
}
这里的outSurface就是从客户端ViewRoot中一步步传入WMS内的Surface对象了。下面来开WMS对Surface对象的处理过程,
已经在java层面上看到了surface的创建,但是ViewRoot的创建(只是简单实例化一个对象,没有意义),SurfaceFlinger创建真正的Surface,WMS获得它。至于Surface怎样传回ViewRoot,还有其他对它的一系列处理,其中大量的代码是在native函数中进行的,这里先不研究native的C++函数。我们优先搞定上层处理。所以我们回到ViewRoot中继续看View的创建于绘制流程。
在performTraversals方法中看看绘制流程,最终看到canvas