一、介绍
- view层级的顶层,实现了View和WindowManager之间的协议,大部分上WindowManagerGlobal类的具体执行类。
- PhoneWindow持有DecorView
二、一些细节 - 线程检查
有mThread变量获取的是创建ViewRootImpl时的线程,用来检查是否在创建线程进行view的操作。比如requestLayout方法有检查线程,如果线程不同则抛异常。
final Thread mThread;
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
- performTraversals
performTraversals依次执行了performMeasure,performlayout,performDraw三个方法 - ViewRootImpl的初始化
在ActivityThread中的handlerResumeActivity执行的是Activity的onResume,这里把decorView添加到windowManager中,而WindowManager具体实现类是WindowManagerImpl
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
// TODO Push resumeArgs into the activity for consideration
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
final Activity a = r.activity;
if (r.window == null && !a.mFinished && willBeVisible) {
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);//decorView添加到windowManagerk
} else {
a.onWindowAttributesChanged(l);
}
}
}
}
WindowManagerImpl的addView方法,WindowManagerGlobal是一个单例类,实际是通过WindowManagerGlobal添加的View
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
WindowManagerGlobal,创建ViewRootImpl,把decorView设置到ViewRootImpl绑定Window所对应的View,并对该View进行测试,布局和绘制。
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
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);
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
ViewRootImpl的setView
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
//完成view的刷新,以及view的绘制
requestLayout();
try {
//window添加到display
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
} catch (RemoteException e) {
} finally {
}
view.assignParent(this);//设置parent
}
}
}
- ViewRootImpl对View的操作
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
@UnsupportedAppUsage
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
private void performTraversals() {
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
performDraw();
}
}
- View的测量
performMeasure执行window对应的view的测量
- ViewRootImpl的performMeasure
- DecorView的measure
- DecorView的onMeasure
- DecorView所有子View的measure
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
if (mView == null) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
- View的布局
performLayout执行Window对应View的布局
- ViewRootImpl的performLayout
- DecorView的layout
- DecorView的onLayout
- DecorView的layoutChildren
- DecorView所有子View的layout
子View的requestLayout方法的执行,会触发 ViewRootImpl方法requstLayout方法的执行,进行重新测试和布局
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
int desiredWindowHeight) {
final View host = mView;
if (host == null) {
return;
}
try {
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
int numViewsRequestingLayout = mLayoutRequesters.size();
if (numViewsRequestingLayout > 0) {
// requestLayout() was called during layout.
// If no layout-request flags are set on the requesting views, there is no problem.
// If some requests are still pending, then we need to clear those flags and do
// a full request/measure/layout pass to handle this situation.
ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
false);
if (validLayoutRequesters != null) {
// Set this flag to indicate that any further requests are happening during
// the second pass, which may result in posting those requests to the next
// frame instead
mHandlingLayoutInLayoutRequest = true;
// Process fresh layout requests, then measure and layout
int numValidRequests = validLayoutRequesters.size();
for (int i = 0; i < numValidRequests; ++i) {
final View view = validLayoutRequesters.get(i);
Log.w("View", "requestLayout() improperly called by " + view +
" during layout: running second layout pass");
view.requestLayout();//View触发自己的requestLayout会触发ViewRootImpl的requestLayout方法,重新进行布局,绘制。
}
measureHierarchy(host, lp, mView.getContext().getResources(),
desiredWindowWidth, desiredWindowHeight);
mInLayout = true;
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
mHandlingLayoutInLayoutRequest = false;
// Check the valid requests again, this time without checking/clearing the
// layout flags, since requests happening during the second pass get noop'd
validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
if (validLayoutRequesters != null) {
final ArrayList<View> finalRequesters = validLayoutRequesters;
// Post second-pass requests to the next frame
getRunQueue().post(new Runnable() {
@Override
public void run() {
int numValidRequests = finalRequesters.size();
for (int i = 0; i < numValidRequests; ++i) {
final View view = finalRequesters.get(i);
Log.w("View", "requestLayout() improperly called by " + view +
" during second layout pass: posting in next frame");
view.requestLayout();
}
}
});
}
}
}
}
}
- View的绘制过程
- ViewRootImpl的performDraw
- ViewRoorImpl的draw
- ViewRootImpl的drawSoftware
- DecorView的draw
- DecorView的dispatchDraw
- DecorView的drawChild
- DecorView所有子View的draw
private void performDraw() {
try {
boolean canUseAsync = draw(fullRedrawNeeded);
} finally {
mIsDrawing = false;
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
private boolean draw(boolean fullRedrawNeeded) {
mAttachInfo.mTreeObserver.dispatchOnDraw();
if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
if (updated) {
requestDrawWindow();
}
mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
} else {
scheduleTraversals();
return false;
if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
scalingRequired, dirty, surfaceInsets)) {
return false;
}
}
}
if (animating) {
mFullRedrawNeeded = true;
scheduleTraversals();
}
return useAsyncReport;
}
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
// Draw with software renderer.
final Canvas canvas;
try {
canvas = mSurface.lockCanvas(dirty);
canvas.setDensity(mDensity);
} catch (Surface.OutOfResourcesException e) {
handleOutOfResourcesException(e);
return false;
} catch (IllegalArgumentException e) {
return false;
} finally {
dirty.offset(dirtyXOffset, dirtyYOffset); // Reset to the original value.
}
try {
mView.draw(canvas);
drawAccessibilityFocusedDrawableIfNeeded(canvas);
} finally {
try {
surface.unlockCanvasAndPost(canvas);
} catch (IllegalArgumentException e) {
return false;
}
}
return true;
}
- 关于异步更新View
View进行视图更新的时候会触发checkThread,校验当前线程是否是ViewRootImpl被创建时所在的线程。而ViewRootImpl的创建是在Activity的onResume生命周期之后。
我们可以再onResume之前在异步线程进行视图更新,因为这个时候不会发生线程校验。
我们可以再异步线程初始化ViewRootImpl同时在该线程进行视图更新。
- onMeasure
- ViewGroup的measureChildren
- ViewGroup的measureChild
- ViewGroup的measureChildWidthMargins
- FrameLayout,LinearLayout,RelativeLayout(View)的onMeasure
- View的measure(),计算一个View应该多大,父View提供大小限制,实际的计算大小是这个方法调用的onMeasure方法,必须被子类复写的。
- onLayout
- ViewGroup的onLayout,layout方法调用,为子View布局
- ViewGroup(View)的layout,为自己以及子View进行布局
- draw
- draw
- onDraw
- dispatchDraw
- drawchild
网友评论