PS:本文系转载文章,浏览原文可读性会更好,文章开端有原文链接
ps:源码是基于 android api 27 来剖析的
在 Android 中,想要获取 View 的一些状态,比如说 View 的宽高产生了扭转,能够应用 ViewTreeObserver 外部接口 OnGlobalLayoutListener 进行注册监听,见名知意,一看名字就晓得它是 ViewTree 的观察者,一个界面蕴含多个 View 造成 ViewTree 的树状构造;ViewTreeObserver 不能间接实例化,只能通过 View 的 getViewTreeObserver 办法获取,对于做 Android 开发的咱们来说,常常接触到 View,所以说学习了解好 ViewTreeObserver 是很有必要的。
ViewTreeObserver 的外部有很多的事件监听接口,蕴含 View 的布局产生扭转、窗口焦点发生变化等监听事件,咱们来看看与 View 相干罕用的 ViewTreeObserver 的外部接口申明;
public interface OnWindowAttachListener { public void onWindowDetached();}public interface OnWindowFocusChangeListener { public void onWindowFocusChanged(boolean hasFocus);}public interface OnGlobalFocusChangeListener { public void onGlobalFocusChanged(View oldFocus, View newFocus);}public interface OnGlobalLayoutListener { public void onGlobalLayout();}public interface OnPreDrawListener { public boolean onPreDraw();}public interface OnDrawListener { public void onDraw();}public interface OnTouchModeChangeListener { public void onTouchModeChanged(boolean isInTouchMode);}public interface OnScrollChangedListener { public void onScrollChanged();}
(1)OnWindowAttachListener 接口:当视图层次结构关联到窗口或与之拆散时回调。
(2)OnWindowFocusChangeListener 接口:当视图层次结构的窗口焦点状态发生变化时回调。
(3)OnGlobalFocusChangeListener接口:当视图树中的焦点状态更改时回调。
(4)OnGlobalLayoutListener 接口:当全局布局状态或视图树中视图的可见性更改时回调。
(5)OnPreDrawListener 接口:当视图行将绘制时回调。
(6)OnDrawListener 接口:当视图树行将绘制时。
(7)OnTouchModeChangeListener 接口:当触摸模式扭转时回调。
(8)OnScrollChangedListener 接口:当视图树中的某些内容被滚动时回调。
咱们来看一下获取 ViewTreeObserver 对象的办法 getViewTreeObserver,它在 View 类中;
public ViewTreeObserver getViewTreeObserver() {
if (mAttachInfo != null) { //1、 return mAttachInfo.mTreeObserver; } if (mFloatingTreeObserver == null) { //2、 mFloatingTreeObserver = new ViewTreeObserver(mContext); } return mFloatingTreeObserver;
}
正文1 中的 ViewTreeObserver 对象是 ViewRootImpl 提供的;正文2 中的 ViewTreeObserver 对象是以后 View 创立的;View 的测量、布局和绘制入口我就不讲了,能够看对Android中View的post办法进行摸索这篇文章,咱们看一下 View 的测量、布局和绘制入口会调用 View 的 dispatchAttachedToWindow 办法;
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
//3、 mAttachInfo = info; ...... if (mFloatingTreeObserver != null) { //4、 info.mTreeObserver.merge(mFloatingTreeObserver); mFloatingTreeObserver = null; } ......
}
正文3 中的 mAttachInfo 关联的是 ViewRootImpl 中的 View.AttachInfo 对象,同一个 View Hierarchy 内所有的 View 中的 mAttachInfo 关联的对象都是 ViewRootImpl 中的 View.AttachInfo 对象;正文4 中的 info.mTreeObserver 是 ViewTreeObserver 对象,正文4 中代码的作用是将以后 View 的 ViewTreeObserver 对象外面的一些接口合并到 ViewRootImpl 中的 View.AttachInfo 对象外面的 ViewTreeObserver ,咱们看看 ViewTreeObserver 的 merge 办法具体实现;
void merge(ViewTreeObserver observer) {
if (observer.mOnWindowAttachListeners != null) { if (mOnWindowAttachListeners != null) { mOnWindowAttachListeners.addAll(observer.mOnWindowAttachListeners); } else { mOnWindowAttachListeners = observer.mOnWindowAttachListeners; } } if (observer.mOnWindowFocusListeners != null) { if (mOnWindowFocusListeners != null) { mOnWindowFocusListeners.addAll(observer.mOnWindowFocusListeners); } else { mOnWindowFocusListeners = observer.mOnWindowFocusListeners; } } if (observer.mOnGlobalFocusListeners != null) { if (mOnGlobalFocusListeners != null) { mOnGlobalFocusListeners.addAll(observer.mOnGlobalFocusListeners); } else { mOnGlobalFocusListeners = observer.mOnGlobalFocusListeners; } } if (observer.mOnGlobalLayoutListeners != null) { if (mOnGlobalLayoutListeners != null) { mOnGlobalLayoutListeners.addAll(observer.mOnGlobalLayoutListeners); } else { mOnGlobalLayoutListeners = observer.mOnGlobalLayoutListeners; } } if (observer.mOnPreDrawListeners != null) { if (mOnPreDrawListeners != null) { mOnPreDrawListeners.addAll(observer.mOnPreDrawListeners); } else { mOnPreDrawListeners = observer.mOnPreDrawListeners; } } if (observer.mOnDrawListeners != null) { if (mOnDrawListeners != null) { mOnDrawListeners.addAll(observer.mOnDrawListeners); } else { mOnDrawListeners = observer.mOnDrawListeners; } } if (observer.mOnTouchModeChangeListeners != null) { if (mOnTouchModeChangeListeners != null) { mOnTouchModeChangeListeners.addAll(observer.mOnTouchModeChangeListeners); } else { mOnTouchModeChangeListeners = observer.mOnTouchModeChangeListeners; } } if (observer.mOnComputeInternalInsetsListeners != null) { if (mOnComputeInternalInsetsListeners != null) { mOnComputeInternalInsetsListeners.addAll(observer.mOnComputeInternalInsetsListeners); } else { mOnComputeInternalInsetsListeners = observer.mOnComputeInternalInsetsListeners; } } if (observer.mOnScrollChangedListeners != null) { if (mOnScrollChangedListeners != null) { mOnScrollChangedListeners.addAll(observer.mOnScrollChangedListeners); } else { mOnScrollChangedListeners = observer.mOnScrollChangedListeners; } } if (observer.mOnWindowShownListeners != null) { if (mOnWindowShownListeners != null) { mOnWindowShownListeners.addAll(observer.mOnWindowShownListeners); } else { mOnWindowShownListeners = observer.mOnWindowShownListeners; } } observer.kill();
}
看到没,一开始先判断以后 View 的 ViewTreeObserver(observer)对象里的相应 Listeners 汇合如果不为空时,而后再判断以后的 ViewTreeObserver 对象(ViewRootImpl 中的 View.AttachInfo 对象外面的 ViewTreeObserver)的相应 Listeners 汇合是否为空,如果以后的 ViewTreeObserver 对象的相应 Listeners 汇合不为空时,就将以后 View 的 ViewTreeObserver 对象里的相应 Listeners 汇合全副增加到以后 ViewTreeObserver 对象的相应 Listeners 汇合,否则将以后 ViewTreeObserver 对象的相应 Listeners 汇合指向以后 View 的 ViewTreeObserver 对象里的相应 Listeners 汇合。
1、OnWindowAttachListener 的触发机会
View 的测量、布局和绘制开始入口是从 ViewRootImpl 的 setView 办法开始的,能够看一下对Android中View的post办法进行摸索这篇文章,ViewRootImpl 的 setView 办法会间接调用 ViewRootImpl 的 performTraversals 办法;
private void performTraversals() {
...... if (mFirst) { ...... //5、 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true); ...... } else { ...... } ...... ......
}
ViewRootImpl 的 performTraversals 办法调用了正文5 中的代码,也就是 ViewTreeObserver 的 dispatchOnWindowAttachedChange 办法,咱们往下看;
final void dispatchOnWindowAttachedChange(boolean attached) {
// NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to // perform the dispatching. The iterator is a safe guard against listeners that // could mutate the list by calling the various add/remove methods. This prevents // the array from being modified while we iterate it. final CopyOnWriteArrayList<ViewTreeObserver.OnWindowAttachListener> listeners = mOnWindowAttachListeners; if (listeners != null && listeners.size() > 0) { for (ViewTreeObserver.OnWindowAttachListener listener : listeners) { //6、 if (attached) listener.onWindowAttached(); //7、 else listener.onWindowDetached(); } }
}
因为正文5 中传入的 boolean 值为 true,所以会调用正文6 中的 OnWindowAttachListener 的 onWindowAttached 办法,正文6 的办法示意视图层次结构附加到窗口时的回调办法;正文7 示意当视图层次结构从窗口拆散时调用的回调办法,它什么时候被调用呢?它是从 Activity 的 onDestroy 办法执行完后被调用的,咱们看一下 ActivityThread 的 handleDestroyActivity 办法;
private void handleDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance) { //8、 ActivityClientRecord r = performDestroyActivity(token, finishing, configChanges, getNonConfigInstance); if (r != null) { ...... if (v != null) { ...... if (r.activity.mWindowAdded) { if (r.mPreserveWindow) { ...... } else { //9、 wm.removeViewImmediate(v); } } ...... } ...... } ......
}
正文8 中的 performDestroyActivity 办法最终调用 Activity 的 onDestroy 办法,有趣味的读者能够跟踪进去看一下;正文9 中的 wm 对象的实现类是 WindowManagerImpl,咱们来看一下 WindowManagerImpl 的 removeViewImmediate 办法;
@Overridepublic void removeViewImmediate(View view) { //10、 mGlobal.removeView(view, true);}
正文10 中的 mGlobal 是 WindowManagerGlobal 类型的对象,咱们得去 WindowManagerGlobal 的 removeView 办法看看;
public void removeView(View view, boolean immediate) {
...... synchronized (mLock) { int index = findViewLocked(view, true); ...... //11、 removeViewLocked(index, immediate); ...... }
}
咱们往下看一下正文11 的代码,也就是 WindowManagerGlobal 的 removeViewLocked 办法;
private void removeViewLocked(int index, boolean immediate) {
ViewRootImpl root = mRoots.get(index); ...... //12、 boolean deferred = root.die(immediate); ......
}
看正文12,WindowManagerGlobal 的 removeViewLocked 办法调用了 ViewRootImpl 的 die 办法;
boolean die(boolean immediate) {
// Make sure we do execute immediately if we are in the middle of a traversal or the damage // done by dispatchDetachedFromWindow will cause havoc on return. if (immediate && !mIsInTraversal) { //13、 doDie(); return false; } ...... return true;
}
看正文13,ViewRootImpl 的 die 办法调用了 ViewRootImpl 的 doDie 办法;
void doDie() {
...... synchronized (this) { ...... if (mAdded) { //14、 dispatchDetachedFromWindow(); } ...... } ......
}
看正文14,ViewRootImpl 的 doDie 办法调用了 ViewRootImpl 的 dispatchDetachedFromWindow 办法;
void dispatchDetachedFromWindow() {
if (mView != null && mView.mAttachInfo != null) { //15、 mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false); ...... } ......
}
看正文15,ViewRootImpl 的 dispatchDetachedFromWindow 办法调用了 ViewTreeObserver 的 dispatchOnWindowAttachedChange 办法,传入的参数是 false,所以 ViewTreeObserver 的 dispatchOnWindowAttachedChange 办法最终调用的是 OnWindowAttachListener 接口的 onWindowDetached 办法,所以 OnWindowAttachListener 接口的 onWindowDetached 办法的调用机会是在 Activity 的 onDestroy 办法之后。
2、OnWindowFocusChangeListener 的触发机会
OnWindowFocusChangeListener 的触发机会是在 View 的绘制完之后,View 的绘制入口的跟踪过程能够看对Android中View的post办法进行摸索这篇文章,View 的绘制入口会调用 ViewRootImpl 的 setView 办法;
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) { if (mView == null) { ...... // 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. //16、 requestLayout(); ...... try { ...... //17、 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); } catch (RemoteException e) { ...... } finally { ...... } ...... } }
}
正文16 的 requestLayout 办法会进行 View 的测量、布局和绘制操作;正文17 中的 mWindowSession 是 IWindowSession 类型,然而它的实现类是什么呢?从 ViewRootImpl 的构造方法能够看出,mWindowSession 的值是通过 WindowManagerGlobal 的 getWindowSession 办法失去的,咱们看一下 WindowManagerGlobal 的 getWindowSession 办法;
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) { if (sWindowSession == null) { try { ...... IWindowManager windowManager = getWindowManagerService(); //18、 sWindowSession = windowManager.openSession( new IWindowSessionCallback.Stub() { @Override public void onAnimatorScaleChanged(float scale) { ValueAnimator.setDurationScale(scale); } }, imm.getClient(), imm.getInputContext()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowSession; }
}
咱们看到正文18 中的 windowManager 尽管是 IWindowManager 类型的,但它的实现类是 WindowManagerService,所以咱们看一下 WindowManagerService 的 openSession 办法;
@Overridepublic IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client, IInputContext inputContext) { if (client == null) throw new IllegalArgumentException("null client"); if (inputContext == null) throw new IllegalArgumentException("null inputContext"); Session session = new Session(this, callback, client, inputContext); //19、 return session;}
看到正文19 没,返回的是 Session 类型的对象,所以 ViewRootImpl 的 mWindowSession 对象的实现类是 Session,咱们看回正文17 的办法,也就是 Session 的 addToDisplay 办法;
@Overridepublic int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { //20、 return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outContentInsets, outStableInsets, outOutsets, outInputChannel);}
正文20 中 mService 是 WindowManagerService,咱们看看 WindowManagerService 的 addWindow 办法;
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { ...... synchronized(mWindowMap) { ...... if (win.canReceiveKeys()) { //21、 focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS, false /*updateInputWindows*/); ...... } ...... } ...... return res;
}
从正文21 能够看出,WindowManagerService 的 addWindow 办法调用了 WindowManagerService 的 updateFocusedWindowLocked 办法;
boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
WindowState newFocus = mRoot.computeFocusedWindow(); if (mCurrentFocus != newFocus) { ...... // This check makes sure that we don't already have the focus // change message pending. mH.removeMessages(H.REPORT_FOCUS_CHANGE); //22、 mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE); ...... final WindowState oldFocus = mCurrentFocus; mCurrentFocus = newFocus; ...... return true; } return false;
}
从正文22 看出,WindowManagerService 的 updateFocusedWindowLocked 办法发送一条音讯给外部类 H,咱们来看看 H 是怎么做相应的解决的;
final class H extends android.os.Handler {
...... @Override public void handleMessage(Message msg) { ...... switch (msg.what) { case REPORT_FOCUS_CHANGE: { WindowState lastFocus; WindowState newFocus; ...... //System.out.println("Changing focus from " + lastFocus // + " to " + newFocus); if (newFocus != null) { if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Gaining focus: " + newFocus); //23、 newFocus.reportFocusChangedSerialized(true, mInTouchMode); notifyFocusChanged(); } ...... } break; } }
}
从正文23 看出,WindowManagerService 的外部类 H 调用了 WindowState 的 reportFocusChangedSerialized 办法;
void reportFocusChangedSerialized(boolean focused, boolean inTouchMode) {
try { //24、 mClient.windowFocusChanged(focused, inTouchMode); } catch (RemoteException e) { } ......
}
正文24 的 mClient 的类型是 IWindow,但它的实现类是 ViewRootImpl 的外部类 W,WindowState 的 reportFocusChangedSerialized 办法调用了 W 的 windowFocusChanged 办法;
static class W extends IWindow.Stub {
...... @Override public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { //25、 viewAncestor.windowFocusChanged(hasFocus, inTouchMode); } } ......
}
从正文25 中看出,W 的 windowFocusChanged 办法调用了 ViewRootImpl 的 windowFocusChanged 办法;
public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
Message msg = Message.obtain(); msg.what = MSG_WINDOW_FOCUS_CHANGED; msg.arg1 = hasFocus ? 1 : 0; msg.arg2 = inTouchMode ? 1 : 0; //26、 mHandler.sendMessage(msg);
}
从正文26 看出,ViewRootImpl 的 windowFocusChanged 办法只是插入了一条音讯,咱们看看 ViewRootImpl 的外部类 ViewRootHandler 对此音讯相应的解决;
final class ViewRootHandler extends Handler {
...... @Override public void handleMessage(Message msg) { switch (msg.what) { ...... case MSG_WINDOW_FOCUS_CHANGED: { if (mAdded) { ...... if (mView != null) { ...... //27、 mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus); ...... } ...... } } break; ...... } }
}
看正文27,ViewRootHandler 对 ViewRootImpl 的 windowFocusChanged 办法发送过去的音讯是这样解决的,mView(实际上是 DecorView) 不为空,那么就调用 ViewTreeObserver 的 dispatchOnWindowFocusChange 办法,咱们往下看;
final void dispatchOnWindowFocusChange(boolean hasFocus) {
// NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to // perform the dispatching. The iterator is a safe guard against listeners that // could mutate the list by calling the various add/remove methods. This prevents // the array from being modified while we iterate it. final CopyOnWriteArrayList<ViewTreeObserver.OnWindowFocusChangeListener> listeners = mOnWindowFocusListeners; if (listeners != null && listeners.size() > 0) { for (ViewTreeObserver.OnWindowFocusChangeListener listener : listeners) { //28、 listener.onWindowFocusChanged(hasFocus); } }
}
从正文28 能够看出,ViewTreeObserver 的 dispatchOnWindowFocusChange 办法调用了 OnWindowFocusChangeListener 接口的 onWindowFocusChanged 办法,所以从以上跟踪的代码过程得出 OnWindowFocusChangeListener 的触发机会是在 View 的测量、布局和绘制之后。
这篇文章写到这里先告一段落了,但还没完,下一篇会持续剖析这篇文章列举进去的但又没剖析触发机会的接口。