慕课网 剖析framework 笔记
4-2 Activity的显示原理
看看相关问题,了解UI涉及的内容;对比他们考察的点,不要弄混:
1,Activity的显示原理:
它是关于Window/DecorView/ViewRoot的概念的
2,Activity的UI刷新机制
是关于Vsync/Choreographer的
3,UI的绘制原理
关于Measure/Layout/Draw的
4,Surface原理
surface/SurfaceFlinger
看看这次的题目:Activity的显示原理:
1,setContentView的原理:
我们在onCreate经常调它,应该非常熟了,但是它的原理是?里面做了什么?
2,Activity在onResume后才能显示的原因?里面做了什么重要的事情?
3,ViewRoot是什么?它是ViewTree的Root View吗?
先看看setContentView
平时新建Activity,都是先给Activity写好布局,然后setContentView加载布局,然后等待显示出来就行了,
看看它的原理:
public void setContentView(int layoutResID){
//拿到window对象,调用它的对象
getWindow().setContentView(layoutResID);
...
}
//它返回window对象,private Window mWindow;
public Window getWindow(){
return mWindow;
}
看看Activity的mWindow对象在哪里初始化的,
是在Activity的attach函数里面init的,
final void attach(Context context,){
.....
//new了一个PhoneWIndow,它是干嘛的?它是手机的window,用来管理手机的窗口,不只是AP内容区域,还管理其他区域
mWindow = new PhoneWIndow(this);
}
讲Activity启动的时候说过,step:
创建Acitivity对象
创建Context对象
准备Application对象
attach上下文,这里不只是context,还有其他重要的变量要init,如window
调用Activity onCreate回调。
所以onCreate的时候,可以拿到mWindow
再看看window的setContextView,
public void setContentView(int layoutResID){
//mContentParent是content view的parent,就是一个view contener,装content view的
if(mContentParent == null){
installDecor();
}
//加载布局用,参数1是要加载的布局的ID,这会生成一个ViewTree,
//参数2是ViewTree的Parent,
//就是给生成的View加入Parent里面
mLayoutInflater.inflate(layoutResID, mContentParent);
}
//看看installDecor做什么用的
//就是创建好一个DecorView,init整个屏幕的页面布局,把自己的布局加入Content里面,
//这里只是加载了布局,建立了ViewTree,顶多算是一个数据结构,页面还不能显示,
//想把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);
}
看看handleResumeActivity
页面显示是在onResume()回调之后,
而前面讲的setContentView是在onCreate里面加载的布局,生成了ViewTree
那么OnResume()又做了什么才能让界面显示?关键就是这一步handleResumeActivity函数
之前讲Activity启动时就讲过了,之前把重点放在生命周期回调,现在重点放在UI上
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(mWindow,...);
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, ...){
//在WMS创建Window相关对象,WMS统一管理所有Window的位置,层次,大小
//这样有什么用?
//对于WMS来说,它不关注AP本地的WIndow对象,也不关注AP端的View,
//它的重要功能就是给AP端的Window分配Surface,并且掌管这些Surface的显示顺序,位置,和尺寸,
//当AP端在Surface绘制完,SF把Surface的图像数据按照WMS里面提供的Surface的层级和位置进行合成,最后显示出来。
return mSerview.addWindow(this, window, seq, attrs,...);
}
//在WMS创建Window相关对象,WMS统一管理所有Window的位置,层次,大小
//这样有什么用?
//对于WMS来说,它不关注AP本地的WIndow对象,也不关注AP端的View,
//它的重要功能就是给AP端的Window分配Surface,并且掌管这些Surface的显示顺序,位置,和尺寸,
//当AP端在Surface绘制完,SF把Surface的图像数据按照WMS里面提供的Surface的层级和位置进行合成,最后显示出来。
WMS的主要作用:
1,分配Surface
2,掌管Surface显示顺序和位置尺寸等
3,控制窗口动画
4,输入事件分发
总结:
ACtivity启动的时候会创建PhoneWindow,
PhoneWindow里面有一个DecorView,它是整个Activity的ViewRree的RootView,
ContentView只是DecorView的一部分
DecorView会对应一个ViewRootImpl对象,它是可以与WMS双向通信的,
ViewRootImpl可以通过IWindowSession向WMS发起binder调用
WMS通过IWindow向ViewRootImpl发起binder调用,
Activity能显示出来的最重要的一步:
为DecorView创建ViewRootImpl对象,并且用ViewRootImpl对象全权负责DecorView的绘制,
ViewRootImpl在WMS里面注册窗口,WMS统一管理窗口的大小,位置,层次,
第一次绘制时,ViewRootImpl还会向WMS申请一个Surface,有了Surface,AP就可以进场绘制。
绘制后,SurfaceFlinger里面就可以按照WMS提供的层级,位置,对Surface进场合成
然后写到FrameBuffer显示出来
总结:说说Activity的显示原理
最好的方式是照着图给整个流程屡屡
1,PhoneWIndow是什么,怎么创建的
2,setContentView原理,DecorView是什么?
4,ViewRoot是什么,有什么作用
5,View的显示原理是什么,这个过程WMS发挥了什么作用