一、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的层级和位置进行合成,最后显示出来。