一、Activity启动步骤
Activity的启动流程为:创建Activity对象 ==> 准备好Application ==> 创建ContextImpl ==> attach应用上下文 ==> 生命周期onCreate回调。
Activity的mWinodw对象就是在attach方法执行的时候创建的。所以我们能够在onCreate的方法中使用mWindow。
final void attach(Context context,){
//new了一个PhoneWIndow,用来管理手机的窗口,不只是AP内容区域,还管理其他区域
mWindow = new PhoneWIndow(this);
//...
}
二、setContentView 的原理
下面我们看一下Activity的setContentView的方法执行的代码,如下:
public void setContentView(int layoutResID){
//mContentParent是content view的parent,即ViewGroup
if(mContentParent == null){
installDecor();
}
//加载布局用,参数1是要加载的布局的ID,这会生成一个ViewTree,参数2是ViewTree的Parent,生成的View会加入Parent里面
mLayoutInflater.inflate(layoutResID, mContentParent);
}
//在installDecor方法中创建好一个DecorView,init整个屏幕的页面布局,把自己的布局加入Content里面,
//这里只是加载了布局,建立了ViewTree的数据结构,此时页面还不能显示,还需后续的很多步骤
private void installDecor(){
//DecorView其实是一个FrameLayout,是手机整个页面的rootView
mDecor = new DecorView(getContext());
//layoutResource是根据window的feature选的一个系统布局,加载好后会添加到DecorView里面
View in = mLayoutInflater.inflate(layoutResource, null);
mDecor.addView(in,...);
//找到了我们的content parent,
mContentParent = findViewById(ID_ANDROID_CONTENT);
}
三、在onResume回调后为何能展示出来布局
关键的函数为handleResumeActivity,其核心代码如下:
final void handleResumeActivity(IBinder token,){
//触发activity的onResume回调,然后再处理UI显示问题
ActivityClientRecord r = performResumeActivity(token,);
final Activity a = r.activity;
if(r.window == null && !a.mFinished){
r.window = r.activity.getWindow();
//拿到了DecorView
View decor = r.window.getDecorView();
ViewManager wm = a.getWindowManager();
a.mDecor = decor;
//把DecorView加到WindowManager里面,后面看看这个函数
wm.addView(decor, l);
}
//让它变得可见,这里不重要,只是触发了一次重绘,
//mDecor.setVisibility(View.VISIBLE);
//真正重要的是谁启动和管理整个View绘制的流程
r.activity.makeVisible();
}
void addView(View view, ViewGroup.LayoutParams params,){
//创建一个ViewRootImpl对象
ViewRoot root = new ViewRootImpl(view.getContext(),);
//DecorView交给ViewRootImpl对象管理
root.setView(view. wparams, panelParentView);
}
public void setView(VIew view,){
//一个ViewRootImpl只能一个管理ViewTree,所以做判断,mView是null才行
if(mView == null){
mView = view;
//1,requestLayout触发第一次绘制
requestLayout();
...
//2,addToDisplay是binder调用
mWindowSession.addToDisplay(mWindow,..);
...
}
}
//分别看看上面的1,2
public void requestLayout(){
....
scheduleTraversals();
}
void scheduleTraversals(){
......
//往Choreographer post一个名为mTraversalRunnable的callback
//这个callback会在下一次vsync到来时被触发。
mChoreographer.postCallback(...,mTraversalRunnable, null);
}
//看看这个callback里面干嘛的
class TraversalRunnable implements Runnable{
public void run(){
//看看它
doTraversal();
}
}
void doTraversal(){
//这是真正执行绘制的地方
performTraversal();
}
//看看它的实现,有4个重要步骤
private void performTraversals(){
....
//1,向WMS申请surface,
relayoutWindow(params,...);
....
//这3个大家很熟悉了,不讲了
performMeasure(childWidthMeasureSpec,...);
....
performLayout(lp, desiredWindowWidth,...);
....
performDraw();
....
}
//1,申请Sureface
int relayoutWindow(WindowManager.LayoutParams params, ...){
//拿到一个WindowSession,调用它的relayout函数,
//它的一个参数是mSurface,这时它还是一个空壳,当函数返回后,mSurface就可以用了
//有了Surface,接下来的绘制就有了Buffer了,绘制好后,送给SurfaceFlinger,
//SF合成好图形,就可以送给FrameBuffer,并显示出来
mWindowSession.relayout(..., mSurface);
}
这里重点提一下mWindowSession.addToDisplay方法:
public void setView(VIew view,){
//一个ViewRootImpl只能一个管理ViewTree,所以做判断,mView是null才行
if(mView == null){
mView = view;
//1,requestLayout触发第一次绘制
requestLayout();
...
//2,addToDisplay是binder调用
mWindowSession.addToDisplay(mWindow,..);
...
}
}
mWindowSession.addToDisplay(mWindow,..);
//WindowSession是干嘛的?
//它是通过WMS的openSession函数返回的binder对象
IWindowManager windowManager = getWindowManagerService();
SWindowSession = windowManager.openSession(...);
//openSession:
IWindowSeesion openSession(IWindowSessionCallback callback,...){
//new了一个Session对象,
//session是用来给应用与WMS通信的,应用拿到session对象就可以向WMS发起binder调用
Session session = new Session(this, callback, client, inputContext);
return session;
}
//现在看看addToDisplay是干嘛的
mWindowSession.addToDisplay(mWindow,..);
//参数mWindow对象是一个binder对象,
//这个binder对象注册到WMS后,AP和WMS就可以双向调用,
static class W extends IWindow.Stub{...}
//addToDisplay调到WMS端的addWindow
public int addToDisplay(IWindow window, int seq, ...){
return mSerview.addWindow(this, window, seq, attrs,...);
}
在WMS中会创建Window相关对象,WMS统一管理所有Window的位置,层次,大小,对于WMS来说,它不关注本地的Window对象,也不关注View,它的重要功能就是给Window分配Surface,并且掌管这些Surface的显示顺序,位置,和尺寸,把Surface的图像数据按照WMS里面提供的Surface的层级和位置进行合成,最后显示出来。