深入解析View展示流程
2018-03-20 21:36
288 查看
1、背景
如果想在Activity中显示一个布局,做法是在Activity的onCreate()方法中使用setContentView()方法设定想要显示的布局,如下所示:@Override protected void onCreate(Bundle paramBundle) { super.onCreate(paramBundle); setContentView(R.layout.mian_layout); }
刚开始接触Android开发的时,只知道只要通过setContentView()方法,把你想要显示的布局资源传递进去即可。这里我将带领大家从源码的角度来分析setContentView()方法是如何把我们设定的布局文件显示出来的。
2、分析
Activity.setContentView()方法通过调用Window.setContentView()方法实现, mWindo对象是在Activity对象被创建的时调用attach()方法进行初始化的,而Window是一个抽象类,它的实现类是PhoneWindow,所以我们直接查看进入PhoneWindow的setContentView( )方法:public void setContentView(int layoutResID) { // 如果mContentParent为null,则通过installDecor()方法进行初始化 if (mContentParent == null) { installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } // inflate()内部就是把id为layoutresID的布局资源初始化为视图对象,并添加 到mContentParent视图容器中 mLayoutInflater.inflate(layoutResID, mContentParent); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); } }
当mContentParent为空时,通过installDecor()方法进行初始化
private void installDecor() { if (mDecor == null) { mDecor = generateDecor(); } if (mContentParent == null) { mContentParent = (ViewGroup)mDecor.findViewById(ID_ANDROID_CONTENT); } }
在这里只关注installDecor()方法内部做的两件事情
创建mDecor对象,该对象就是用户可见视图的顶级对象
从mDecor中查找到mContentParent视图
这里涉及到DecorView视图的内部结构这个知识点,想要深入了解,请查看《DecorView内部结构解析》。这里我们只需知道mDecor是最顶层的View,mContentParent是mDecor中的一个子View。
接下来就是调用mLayoutInflater.inflate(layoutResID, mContentParent)。
该方法的作用是更加资源ID创建一个视图对象,并添加到mContentParent中,
对于Layout.inflate()的内部实现原理在《View的创建过程解析》有分析。
这里总结一下:setContentView()方法完成的工作就是创建一个顶级的mDecor ,接着根据布局资源ID创建一个视图对象,并把该对象加入到mDecor中。
上面的操作完成后,界面还是未展示出来了,所以我们继续分析。
当Activity.onResume( )方法被回调后,界面才对用户可见。所以查看ActivityThread.handleResumeActivity( )回调Activity.onResume( )后的操作。
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) { // 通过performResumeActivity()方法回调onResume()方法 ActivityClientRecord r = performResumeActivity(token, clearHide); final Activity a = r.activity; if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); // 从window中获取mDecorView,该View中已经包含了我们需要显示的View, // 即通过setContentView()方法添加到mContentParent的View View decor = r.window.getDecorView(); decor.setVisibility(View.INVISIBLE); ViewManager wm = a.getWindowManager(); // 为decor创建布局参数params WindowManager.LayoutParams params = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; if (a.mVisibleFromClient) { a.mWindowAdded = true; // 调用WindowManager.addView()方法添加decor wm.addView(decor, params); } } }
对于handleResumeActivity( )方法做了很多工作。但是我们这里只关注两个操作
通过performResumeActivity()方法回调onResume( )
为decor创建布局参数params,并调用WindowManager.addView(decor, params)方法添加decor
WindowManager是一个接口,该接口的实现类为WindowManagerImpl,我们查看addView( )方法,该方法的实际操作还是调用mGlobal对象来完成。
@Override public void addView(View view, ViewGroup.LayoutParams params) { mGlobal.addView(view, params, mDisplay, mParentWindow); }
在WindowManagerImpl内部,很多操作都是mGlobal来实现的,mGlobal是WindowMangerGlobal对象,可以理解为WindowMangerImpl是WindowMangerGlobal的代理。
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { ViewRootImpl root; View panelParentView = null; synchronized (mLock) { // 创建一个ViewRootImpl对象 root = new ViewRootImpl(view.getContext(), display); // 保存root和view mViews.add(view); mRoots.add(root); } try { // 把View加入到root对象 root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { throw e; } }
ViewRootImpl对象的setView( )方法比较多,这里只精简出我们关心的处理
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { ... if (mView == null) { mView = view; } // 第一次尝试对DecorView进行测量,布局 requestLayout(); try { // 这里是重点,通过addToDisplay方法向WindowManagerService添加一个Window res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); } catch (RemoteException e) { } ... } }
添加处理都是在WindowManagerService这个服务中实现,这里就不深究addToDisplay方法。 我们只需知道mWindowSession是本地向WindowManagerService发送消息的通道,mWindow是WindowManagerService 向本地发送消息的通道。调用addToDisplay方法其实就是本地通知WindowManagerService需要添加一个window, WindowManagerService接收到通知后进行相应的操作并通过mWindow向本地发送操作结果。
当WindowManagerService处理完后,向ViewRootImpl发送通知,ViewRootImpl就会调用requestLayout( )方法,在requestLayout( )方法中最后会转到performTraversals( )方法,该方法代码非常的多,但我们只关注的几行代码。该方法内部就会启动DecorView的measure、Layout、draw三部曲操作,当这三个步骤走完后,DecorView就是可见的了,measure、Layout、draw三部曲是我们下一节要分析的内容。
相关文章推荐
- Android视图绘制流程完全解析,带你一步步深入了解View
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- (郭霖)Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二) ---站在巨人的肩膀上学习总结
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)
- Android视图绘制流程完全解析,带你一步步深入了解View(二)