ViewRootImpl与Activity,Window,WindowManagerService的关系比较紧密,初次接触很难理解它们之间的关系
简单来说ViewRootImpl负责管理Activity的view,主要处理view的测量,布局,绘制等事务,即measure,layout和traversal
1.ViewRootImpl的创建与初始化
Activity创建的时候会走到WindowManagerGlobal的addView方法,这里面会创建一个ViewRootImpl对象
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
用于构造ViewRootImpl的参数view是一个DecorView对象,继续看构造函数的实现
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
mDisplay = display;
mBasePackageName = context.getBasePackageName();
mThread = Thread.currentThread();
mLocation = new WindowLeaked(null);
mLocation.fillInStackTrace();
mWidth = -1;
mHeight = -1;
mDirty = new Rect();
mTempRect = new Rect();
mVisRect = new Rect();
mWinFrame = new Rect();
mWindow = new W(this);
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
mViewVisibility = View.GONE;
mTransparentRegion = new Region();
mPreviousTransparentRegion = new Region();
mFirst = true; // true for the first time the view is added
mAdded = false;
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
context);
mAccessibilityManager = AccessibilityManager.getInstance(context);
mAccessibilityManager.addAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager, mHandler);
mHighContrastTextManager = new HighContrastTextManager();
mAccessibilityManager.addHighTextContrastStateChangeListener(
mHighContrastTextManager, mHandler);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
mFallbackEventHandler = new PhoneFallbackEventHandler(context);
mChoreographer = Choreographer.getInstance();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
if (!sCompatibilityDone) {
sAlwaysAssignFocus = true;
sCompatibilityDone = true;
}
loadSystemProperties();
}
里面大部分都和窗口的参数相关,比较重要的成员有这么几个
- mContext 表面其对应的activity
- mWindowSession 建立与WMS的联系,唯一性的标识
- mChreographer 处理视图的刷新
完成ViewRootImpl的构造之后就会把decorView以及窗口的params给设置过去
2.requestLayout
setView方法的内容比较多,里面会执行到requestLayout(),看一下这个函数的具体实现
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
checkThread用于线程检查,继续看scheduleTraversals方法
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
变量mTraversalScheduled的存在是防止重复调用,如果当面没有正在进行布局的操作,则向Choreographer注册了一个回调,我们知道,Choreographer是负责接收vsync信号并且将其发送到各个使用的客户端,所以注册回调之后,等待vsync来了之后就可以进行相应的操作了
注册的callback类型是CALLBACK_TRAVERSAL,接收到vsync信号之后重新对view进行layout,对于ViewRootImpl来说是执行mTraversalRunnable,看一下这个runnable
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
可见,最终是走到了performTraversals()方法,performTraversals是view绘制的关键方法,但是这个方法比较长而且复杂,放到后面再讲
网友评论