源码版本:28
Activity打开之后,再onResume中 尝试去获取View的宽高发现获取失败.这个时候才发现对Activity onResume之后的操作并未看过.所以追一下onResume之后的执行逻辑.
问题:
为什么再Activity的onResume() 生命周期中获取不到View的宽高
答:因为再Activity的onResume的生命周期执行的时候View的根布局DecorView还未加载到Window上 宽高未测量.
流程:
1.ResumeActivityItem.execute()
----> (ActivityThread) client.handleResumeActivity()
----> 执行ActivityThread的handleResumeActivity() 方法
1:ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason) 执行Activity的onResume()方法
2:将Activity的DecorView 添加到Window上
a.mWindowAdded = true; wm.addView(decor, l);*
---> ViewRootImpl root.setView(view, wparams, panelParentView);
---> ViewRootImpl requestLayout();
---> ViewRootImpl scheduleTraversals()
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
// 重点:处理onAttchWindow()
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
// 重点:处理onWindowFocusChanged()
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
1:Activity onResume生命周期执行后Android系统如何操作的
1.1 调用ActivityThread的 handleResumeActivity()方法
ResumeActivityItem.java
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
//ActivityThread 继承了 ClientTransactionHandler client 是ActivtyThread传递过来的对象
client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
"RESUME_ACTIVITY");
}
1.2 调用Activity的onResume()和调用后Window添加View
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// 重点:执行Activity的onResume()方法
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
if (r == null) {
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);
//获取的是WindowManagerImpl
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;
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
//将DecorView添加到 Window上
a.mWindowAdded = true;
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
....
}
1.3 将DecorView 添加到Window上
1:WindowManagerImpl .java
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
}
2: WindowManagerGlobal .java
public final class WindowManagerGlobal {
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
ViewRootImpl root;
View panelParentView = null;
.....
//重点 创建ViewRootImpl
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 {
//重点: 设置View root 是ViewRootImpl
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
}
1.4.ViewRootImpl .setView() 设置View
1: ViewRootImpl requestLayout()
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
//重点:view 是一个DecorView
synchronized (this) {
....
// 在添加到窗口管理器之前安排第一个布局,以确保我们在从系统接收任何其他事件之前进行重新发布。
requestLayout();
....
}
2:requestLayout()
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
3:scheduleTraversals()
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
// 重点:处理onAttchWindow()
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
// 重点:处理onWindowFocusChanged()
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
2:Activity onAttchWindow() 和onWindowFocusChanged()方法的执行
2.1 执行onAttchWindow()方法
2.1.1ViewRootImpl 执行绘制和调用ActivityonAttchWindow()方法
TraversalRunnable类
1:执行doTraversal()方法
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
2:doTraversal()
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
....
performTraversals();
....
}
}
2.1.2 执行onAttchWindow和View的生命周期的方法
核心方法:
- host.dispatchAttachedToWindow(mAttachInfo, 0);分发生命周期
- performMeasure() 分发measure() 执行之后才能获取控件的宽高
- performLayout分发View layout()
- performDraw 分发View draw()
private void performTraversals() {
// host是DecorView
final View host = mView;
if (host == null || !mAdded)
return;
...
// ViewRootImpl(Context context, Display display) 创建的时候 mFirst 值为true
if (mFirst) {
...
//重点: host是DecorView执行了DecorView 的 dispatchAttachedToWindow
host.dispatchAttachedToWindow(mAttachInfo, 0);
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
dispatchApplyInsets(host);
} else {
desiredWindowWidth = frame.width();
desiredWindowHeight = frame.height();
if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
mFullRedrawNeeded = true;
mLayoutRequested = true;
windowSizeMayChange = true;
}
}
...
if (!mStopped || mReportNextDraw) {
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
(relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
|| mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
// 执行View 的onMeasure()方法 调用此方法 才给View的宽高赋值
//Activity onResume()方法是在调用测量后执行的所以获取不了宽高
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
int width = host.getMeasuredWidth();
int height = host.getMeasuredHeight();
boolean measureAgain = false;
if (lp.horizontalWeight > 0.0f) {
width += (int) ((mWidth - width) * lp.horizontalWeight);
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
MeasureSpec.EXACTLY);
measureAgain = true;
}
if (lp.verticalWeight > 0.0f) {
height += (int) ((mHeight - height) * lp.verticalWeight);
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
MeasureSpec.EXACTLY);
measureAgain = true;
}
//处理二次测量
if (measureAgain) {
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
layoutRequested = true;
}
}
} else {
maybeHandleWindowMove(frame);
}
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
//重点:View.执行onLayout方法
performLayout(lp, mWidth, mHeight);
...
}
if (triggerGlobalLayoutListener) {
mAttachInfo.mRecomputeGlobalAttributes = false;
mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
}
...
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
if (!cancelDraw && !newSurface) {
...
//重点:执行View的Draw方法
performDraw();
} else {
if (isViewVisible) {
// Try again
scheduleTraversals();
} else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).endChangingAnimations();
}
mPendingTransitions.clear();
}
}
mIsInTraversal = false;
}
2.1.3 (DecorView)host.dispatchAttachedToWindow(mAttachInfo, 0); 分发事件
DecorView继承树
DecorView--->FrameLayout--->ViewGroup--->View
DecorView 没有 dispatchAttachedToWindow()方法调用到ViewGroup的此方法
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
@Override
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
//向下调用View的dispatchAttachedToWindow()
super.dispatchAttachedToWindow(info, visibility);
mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
final View child = children[i];
//调用子View的dispatchAttachedToWindow()
child.dispatchAttachedToWindow(info,
combineVisibility(visibility, child.getVisibility()));
}
final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
for (int i = 0; i < transientCount; ++i) {
View view = mTransientViews.get(i);
view.dispatchAttachedToWindow(info,
combineVisibility(visibility, view.getVisibility()));
}
}
@Override
public void dispatchWindowFocusChanged(boolean hasFocus) {
/ /向下调用View的dispatchWindowFocusChanged()
super.dispatchWindowFocusChanged(hasFocus);
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
//分发子View的dispatchWindowFocusChanged()
children[i].dispatchWindowFocusChanged(hasFocus);
}
}
}
1.3 调用View的方法
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
public void dispatchWindowFocusChanged(boolean hasFocus) {
//重点 :
// 因为DecorView 实现了onWindowFocusChanged()所以回调给DecorView onAttachedToWindow()
onWindowFocusChanged(hasFocus);
}
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
//重点 :
// 因为DecorView 实现了onAttachedToWindow()所以回调给DecorView onAttachedToWindow()
onAttachedToWindow();
ListenerInfo li = mListenerInfo;
final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners =
li != null ? li.mOnAttachStateChangeListeners : null;
if (listeners != null && listeners.size() > 0) {
for (OnAttachStateChangeListener listener : listeners) {
listener.onViewAttachedToWindow(this);
}
}
onVisibilityChanged(this, visibility);
if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) {
refreshDrawableState();
}
needGlobalAttributesUpdate(false);
notifyEnterOrExitForAutoFillIfNeeded(true);
}
}
2.1.4 DecorView
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL) && !hasWindowFocus
&& mWindow.mPanelChordingKey != 0) {
mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL);
}
final Window.Callback cb = mWindow.getCallback();
if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
// mWindow 是Activity创建的PhoneWindow 且Activity实现了Window.Callback的接口
// mWindow.getCallback 是Activity的创建的onWindowFocusChanged()
//所以 cb.onAttachtoWindow()回调到了Activity的实现方法中
cb.onWindowFocusChanged(hasWindowFocus);
}
if (mPrimaryActionMode != null) {
mPrimaryActionMode.onWindowFocusChanged(hasWindowFocus);
}
if (mFloatingActionMode != null) {
mFloatingActionMode.onWindowFocusChanged(hasWindowFocus);
}
updateElevation();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// mWindow 是Activity创建的PhoneWindow 且Activity实现了Window.Callback的接口
// mWindow.getCallback 是Activity的创建的onAttachedToWindow()
//所以 cb.onAttachtoWindow()回调到了Activity的实现方法中
final Window.Callback cb = mWindow.getCallback();
if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
cb.onAttachedToWindow();
}
if (mFeatureId == -1) {
mWindow.openPanelsAfterRestore();
}
if (!mWindowResizeCallbacksAdded) {
getViewRootImpl().addWindowCallbacks(this);
mWindowResizeCallbacksAdded = true;
} else if (mBackdropFrameRenderer != null) {
mBackdropFrameRenderer.onConfigurationChange();
}
mWindow.onViewRootImplSet(getViewRootImpl());
}
}
Activity attach()方法
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback, WindowControllerCallback,
AutofillManager.AutofillClient {
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
//创建PhoneWindow
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
// 设置Window.Callback 监听
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
if (voiceInteractor != null) {
if (lastNonConfigurationInstances != null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
Looper.myLooper());
}
}
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
enableAutofillCompatibilityIfNeeded();
}
}
2.2 执行onWindowFocusChanged()方法
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
// 重点:处理onAttchWindow()
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
// 重点:处理onWindowFocusChanged()
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);执行之后调用了ActivityonAttchWindow()方法和绘制和布局了View 将布局添加到了Window上,接着就要处理焦点问题了
2.2.1处理Activity和View的焦点
1:
void scheduleConsumeBatchedInput() {
if (!mConsumeBatchedInputScheduled) {
mConsumeBatchedInputScheduled = true;
//重点
mChoreographer.postCallback(Choreographer.CALLBACK_INPUT,
mConsumedBatchedInputRunnable, null);
}
}
2:
final class ConsumeBatchedInputRunnable implements Runnable {
@Override
public void run() {
//重点
doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
}
}
3:
void doConsumeBatchedInput(long frameTimeNanos) {
if (mConsumeBatchedInputScheduled) {
mConsumeBatchedInputScheduled = false;
if (mInputEventReceiver != null) {
if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
&& frameTimeNanos != -1) {
// If we consumed a batch here, we want to go ahead and schedule the
// consumption of batched input events on the next frame. Otherwise, we would
// wait until we have more input events pending and might get starved by other
// things occurring in the process. If the frame time is -1, however, then
// we're in a non-batching mode, so there's no need to schedule this.
scheduleConsumeBatchedInput();
}
}
//重点
doProcessInputEvents();
}
}
4:
void doProcessInputEvents() {
// Deliver all pending input events in the queue.
while (mPendingInputEventHead != null) {
QueuedInputEvent q = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
if (mPendingInputEventHead == null) {
mPendingInputEventTail = null;
}
q.mNext = null;
mPendingInputEventCount -= 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
long eventTime = q.mEvent.getEventTimeNano();
long oldestEventTime = eventTime;
if (q.mEvent instanceof MotionEvent) {
MotionEvent me = (MotionEvent)q.mEvent;
if (me.getHistorySize() > 0) {
oldestEventTime = me.getHistoricalEventTimeNano(0);
}
}
mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
//重点
deliverInputEvent(q);
}
....
}
5:
private void deliverInputEvent(QueuedInputEvent q) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
q.mEvent.getSequenceNumber());
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStage stage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (q.mEvent instanceof KeyEvent) {
mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
}
if (stage != null) {
//核心方法
handleWindowFocusChanged();
stage.deliver(q);
} else {
finishInputEvent(q);
}
}
2.2.2 ViewRootImpl 核心方法
private void handleWindowFocusChanged() {
final boolean hasWindowFocus;
final boolean inTouchMode;
synchronized (this) {
if (!mWindowFocusChanged) {
return;
}
mWindowFocusChanged = false;
hasWindowFocus = mUpcomingWindowFocus;
inTouchMode = mUpcomingInTouchMode;
}
// DecorView 已经添加
if (mAdded) {
profileRendering(hasWindowFocus);
if (hasWindowFocus) {
...
mAttachInfo.mHasWindowFocus = hasWindowFocus;
mLastWasImTarget = WindowManager.LayoutParams
.mayUseInputMethod(mWindowAttributes.flags);
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
imm.onPreWindowFocus(mView, hasWindowFocus);
}
if (mView != null) {
mAttachInfo.mKeyDispatchState.reset();
//重点:执行DecorView的dispatchWindowFocusChanged() 但是DecorView的此方法是父类ViewGroup的方法 所以调用到了ViewGroup方法
mView.dispatchWindowFocusChanged(hasWindowFocus);
mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
if (mAttachInfo.mTooltipHost != null) {
mAttachInfo.mTooltipHost.hideTooltip();
}
}
....
mFirstInputStage.onWindowFocusChanged(hasWindowFocus);
}
2.2.3 DecorView 方法执行
DecorView继承树
DecorView--->FrameLayout--->ViewGroup--->View
- 执行到了ViewGroup.java dispatchWindowFocusChanged()方法
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
@Override
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
//向下调用View的dispatchAttachedToWindow()
super.dispatchAttachedToWindow(info, visibility);
mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
final View child = children[i];
//调用子View的dispatchAttachedToWindow()
child.dispatchAttachedToWindow(info,
combineVisibility(visibility, child.getVisibility()));
}
final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
for (int i = 0; i < transientCount; ++i) {
View view = mTransientViews.get(i);
view.dispatchAttachedToWindow(info,
combineVisibility(visibility, view.getVisibility()));
}
}
@Override
public void dispatchWindowFocusChanged(boolean hasFocus) {
/ /向下调用View的dispatchWindowFocusChanged()
super.dispatchWindowFocusChanged(hasFocus);
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
//分发子View的dispatchWindowFocusChanged()
children[i].dispatchWindowFocusChanged(hasFocus);
}
}
}
- View.java 调用View 的dispatchWindowFocusChanged()方法
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
public void dispatchWindowFocusChanged(boolean hasFocus) {
//重点 :
// 因为DecorView 实现了onWindowFocusChanged()所以回调给DecorView onAttachedToWindow()
onWindowFocusChanged(hasFocus);
}
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
//重点 :
// 因为DecorView 实现了onAttachedToWindow()所以回调给DecorView onAttachedToWindow()
onAttachedToWindow();
ListenerInfo li = mListenerInfo;
final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners =
li != null ? li.mOnAttachStateChangeListeners : null;
if (listeners != null && listeners.size() > 0) {
for (OnAttachStateChangeListener listener : listeners) {
listener.onViewAttachedToWindow(this);
}
}
onVisibilityChanged(this, visibility);
if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) {
refreshDrawableState();
}
needGlobalAttributesUpdate(false);
notifyEnterOrExitForAutoFillIfNeeded(true);
}
}
- DecorView.java 回调到了onAttachedToWindow()
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL) && !hasWindowFocus
&& mWindow.mPanelChordingKey != 0) {
mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL);
}
final Window.Callback cb = mWindow.getCallback();
if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
// mWindow 是Activity创建的PhoneWindow 且Activity实现了Window.Callback的接口
// mWindow.getCallback 是Activity的创建的onWindowFocusChanged()
//所以 cb.onAttachtoWindow()回调到了Activity的实现方法中
cb.onWindowFocusChanged(hasWindowFocus);
}
if (mPrimaryActionMode != null) {
mPrimaryActionMode.onWindowFocusChanged(hasWindowFocus);
}
if (mFloatingActionMode != null) {
mFloatingActionMode.onWindowFocusChanged(hasWindowFocus);
}
updateElevation();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// mWindow 是Activity创建的PhoneWindow 且Activity实现了Window.Callback的接口
// mWindow.getCallback 是Activity的创建的onAttachedToWindow()
//所以 cb.onAttachtoWindow()回调到了Activity的实现方法中
final Window.Callback cb = mWindow.getCallback();
if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
cb.onAttachedToWindow();
}
if (mFeatureId == -1) {
mWindow.openPanelsAfterRestore();
}
if (!mWindowResizeCallbacksAdded) {
getViewRootImpl().addWindowCallbacks(this);
mWindowResizeCallbacksAdded = true;
} else if (mBackdropFrameRenderer != null) {
mBackdropFrameRenderer.onConfigurationChange();
}
mWindow.onViewRootImplSet(getViewRootImpl());
}
}
总结:
Activity onResume()执行之后Window才将xml解析的View add到了Window上,因为onResume()在window.addView()之前 所以获取不了View的宽高.
window.addView()执行的过程中触发了两个Activity方法onAttchWindow()和onWindowFocusChanged().
Window.addView()触发 ViewRootImpl 的
--->setView()
--->requestLayout();
--->scheduleTraversals()
--->mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);执行onAttchWindow()
--->scheduleConsumeBatchedInput()
--->Choreographer.postCallback(Choreographer.CALLBACK_INPUT,mConsumedBatchedInputRunnable, null);
--->doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
--->doProcessInputEvents()
--->deliverInputEvent(q);
---> handleWindowFocusChanged();
--->mView.dispatchWindowFocusChanged(hasWindowFocus);
//执行分发焦点
方法 首先触发了onAttchWindow() 然后只想View的measure,layout和draw()方法 当View的这些方法执行之后才有了View的宽高.
View 绘制完成后 再执行dispatchWindowFocusChanged() 所以再焦点分发的回调中能获取Activity的焦点和 View的宽高.
网友评论