问题:为什么在Activity的onCreate()、onStart()、onResume()方法中直接通过 View.getHeight() 和 View.getMeasuredHeight() 方法都拿不到View的宽高呢?
首先我们来看Activity的onResume是在什么时候被调用的,在ActivityThread.java 中执行handleResumeActivity()方法
/***
*在ActivityThread.java 中
*/
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// TODO Push resumeArgs into the activity for consideration
//performResumeActivity执行Activity的onResume()方法
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); //注释 Ⅰ
if (r == null) {
// We didn't actually resume the activity, so skipping any follow-up actions.
return;
}
final Activity a = r.activity;
final int forwardBit = isForward
? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
try {
willBeVisible = ActivityManager.getService().willActivityBeVisible(
a.getActivityToken());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
// Normally the ViewRoot sets up callbacks with the Activity
// in addView->ViewRootImpl#setView. If we are instead reusing
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
//开始添加 view ,在wm.addView()方法中会真正调用view的测量、布局、绘制
wm.addView(decor, l); //注释 Ⅳ
} else {
a.onWindowAttributesChanged(l);
}
}
// If the window has already been added, but during resume
// we started another activity, then don't yet make the
// window visible.
} else if (!willBeVisible) {
if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
//省略部分代码...
}
/** 注释 Ⅰ 的实现
* 在ActivityThread.java中
*/
public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
String reason) {
//省略部分代码..
r.activity.performResume(r.startsNotResumed, reason); //注释 Ⅱ
}
/** 注释 Ⅱ 的实现
*在 Activity.java 中
*/
final void performResume(boolean followedByPause, String reason) {
//省略其他代码...
// mResumed is set by the instrumentation
mInstrumentation.callActivityOnResume(this); //注释 Ⅲ
}
/** 注释 Ⅲ 的实现
* Instrumentation.java中
*/
public void callActivityOnResume(Activity activity) {
activity.mResumed = true;
//在这里就真正执行了Activity的onResume()方法的调用
activity.onResume();
//省略部分代码..
}
因此在ActivityThread类中的handleResumeActivity()里面调用performResumeActivity()完成了调用Activity类的onResume()方法的调用。紧接在handleResumeActivity()方法执行完performResumeActivity()后,又执行了wm.addView() (注释 Ⅳ),完成View的添加(包括测量、布局、绘制)。
在handleResumeActivity()方法中的wm.addView()添加view,即调用了WindowManager的实现了WindowManagerImpl中的addView()方法,然后在。WindowManagerImpl中的addView()方法里面又调用WindowManagerGlobal的addView()方法去添加view
/**
* WindowManagerImpl.java
*/
public final class WindowManagerImpl implements WindowManager {
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); //注释 Ⅴ
}
}
/** 注释 Ⅴ 的实现
* WindowManagerGlobal.java
*/
public final class WindowManagerGlobal {
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);
//添加view到List集合中
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
//root是ViewRootImpl 在里面实现view的添加
root.setView(view, wparams, panelParentView); //注释 Ⅵ
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
}
在ViewRootImpl中的setView()方法里面会调用requestLayout()方法请求布局
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
/** 注释 Ⅵ 的实现
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
//省略部分代码....
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
//请求布局
requestLayout(); //注释 Ⅶ
//省略部分代码....
}
/** 注释 Ⅶ 的实现
* 在requestLayout()中调用scheduleTraversals()
*/
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals(); //注释Ⅷ
}
}
/** 注释 Ⅷ 的实现
*在scheduleTraversals()方法中有个异步操作mTraversalRunnable
*/
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); //注释 Ⅸ
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
/** 注释 Ⅸ 的实现
*ViewRootImpl里的内部类,执行doTraversal()
*/
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal(); // 注释 Ⅹ
}
}
/** 注释 Ⅹ 的实现
*在doTraversal方法中执行 performTraversals();
*/
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
//在此方法中真正调用了ViewGroup的布局、测量、绘制
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
/**
* 在performTraversals()方法中执行View的测量、布局、绘制
*/
private void performTraversals() {
//省略部分代码..
// Ask host how big it wants to be
//测量、布局、绘制
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
performLayout(lp, mWidth, mHeight);
performDraw();
}
}
在ViewRootImpl类中 performMeasure()的实现
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
if (mView == null) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
//开始view的测量,这里的 mView是 DecorView
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
在ViewRootImpl类中 performLayout()的实现
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,int desiredWindowHeight) {
mLayoutRequested = false;
mScrollMayChange = true;
mInLayout = true;
final View host = mView;
if (host == null) {
return;
}
if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
Log.v(mTag, "Laying out " + host + " to (" +
host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
try {
//开始布局 这里的host是 DecorView
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
}
//省略部分代码....
}
在ViewRootImpl类中performDraw()的实现
private void performDraw() {
//省略其他代码....
//开始绘制
boolean canUseAsync = draw(fullRedrawNeeded);
}
之所以在onCreate()、onStart()、onResume()里通过View.getHeight 和 View.getMeasuredHeight()方法拿到的都是0,是因为在onResume()方法执行完后才进行view的添加(包括测量、布局、绘制)。
网友评论