1. 程式人生 > >017.View與窗口:AttachInfo

017.View與窗口:AttachInfo

elpa ecif toc metrics 通過 onf asset nali 一般來說

每一個View都需要依賴於窗口來顯示,而View和窗口的關系則是放在View.AttachInfo中,關於View.AttachInfo的文章少,因為這個是View的內部類而且不是公共的,在應用層用的很少,只有在ViewRootImpl等類中才用到了,不過我覺得這個還是有點學習的必要,因此在這篇文章中就從源碼入手學習下AttachInfo這個類。


AttachInfo 看到這個類名,我們就知道,他是代表著綁定的信息,View.AttachInfo 裏面的信息,就是View和Window之間的信息。每一個被添加到窗口上的View我們都會看到有一個AttachInfo,比如我們看DecorView和Window的綁定,可以在ViewRootImpl#perfromTraversals方法中看到:

[java] view plain copy 技術分享技術分享
  1. final View.AttachInfo attachInfo = mAttachInfo;
  2. final int viewVisibility = getHostVisibility();
  3. boolean viewVisibilityChanged = mViewVisibility != viewVisibility
  4. || mNewSurfaceNeeded;
  5. WindowManager.LayoutParams params = null;
  6. if (mWindowAttributesChanged) {
  7. mWindowAttributesChanged = false;
  8. surfaceChanged = true;
  9. params = lp;
  10. }
  11. CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
  12. if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
  13. params = lp;
  14. mFullRedrawNeeded = true;
  15. mLayoutRequested = true;
  16. if (mLastInCompatMode) {
  17. params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
  18. mLastInCompatMode = false;
  19. } else {
  20. params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
  21. mLastInCompatMode = true;
  22. }
  23. }
  24. mWindowAttributesChangesFlag = 0;
  25. Rect frame = mWinFrame;
  26. if (mFirst) {
  27. mFullRedrawNeeded = true;
  28. mLayoutRequested = true;
  29. if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
  30. || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
  31. // NOTE -- system code, won‘t try to do compat mode.
  32. Point size = new Point();
  33. mDisplay.getRealSize(size);
  34. desiredWindowWidth = size.x;
  35. desiredWindowHeight = size.y;
  36. } else {
  37. DisplayMetrics packageMetrics =
  38. mView.getContext().getResources().getDisplayMetrics();
  39. desiredWindowWidth = packageMetrics.widthPixels;
  40. desiredWindowHeight = packageMetrics.heightPixels;
  41. }
  42. // For the very first time, tell the view hierarchy that it
  43. // is attached to the window. Note that at this point the surface
  44. // object is not initialized to its backing store, but soon it
  45. // will be (assuming the window is visible).
  46. attachInfo.mSurface = mSurface;
  47. // We used to use the following condition to choose 32 bits drawing caches:
  48. // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
  49. // However, windows are now always 32 bits by default, so choose 32 bits
  50. attachInfo.mUse32BitDrawingCache = true;
  51. attachInfo.mHasWindowFocus = false;
  52. attachInfo.mWindowVisibility = viewVisibility;
  53. attachInfo.mRecomputeGlobalAttributes = false;
  54. viewVisibilityChanged = false;
  55. mLastConfiguration.setTo(host.getResources().getConfiguration());
  56. mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
  57. // Set the layout direction if it has not been set before (inherit is the default)
  58. if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
  59. host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
  60. }
  61. host.dispatchAttachedToWindow(attachInfo, 0);


AttachInfo 會通過View的diapatchAttachedTowWindow分發給View。如果是一個ViewGroup 那麽這個這個AttachInfo也會分發給所有子View,以引用的方式。 下面我們可以看下AttachInfo這個類,這個類是View的內部類,不是聲明為public的,所以只有view這個包中的類才用到。
[java] view plain copy 技術分享技術分享
  1. static class AttachInfo {
  2. interface Callbacks {
  3. void playSoundEffect(int effectId);
  4. boolean performHapticFeedback(int effectId, boolean always);
  5. }
  6. /**
  7. * InvalidateInfo is used to post invalidate(int, int, int, int) messages
  8. * to a Handler. This class contains the target (View) to invalidate and
  9. * the coordinates of the dirty rectangle.
  10. *
  11. * For performance purposes, this class also implements a pool of up to
  12. * POOL_LIMIT objects that get reused. This reduces memory allocations
  13. * whenever possible.
  14. */
  15. static class InvalidateInfo {
  16. private static final int POOL_LIMIT = 10;
  17. private static final SynchronizedPool<InvalidateInfo> sPool =
  18. new SynchronizedPool<InvalidateInfo>(POOL_LIMIT);
  19. View target;
  20. int left;
  21. int top;
  22. int right;
  23. int bottom;
  24. public static InvalidateInfo obtain() {
  25. InvalidateInfo instance = sPool.acquire();
  26. return (instance != null) ? instance : new InvalidateInfo();
  27. }
  28. public void recycle() {
  29. target = null;
  30. sPool.release(this);
  31. }
  32. }
  33. final IWindowSession mSession;
  34. final IWindow mWindow;
  35. final IBinder mWindowToken;
  36. final Display mDisplay;
  37. final Callbacks mRootCallbacks;
  38. HardwareCanvas mHardwareCanvas;
  39. IWindowId mIWindowId;
  40. WindowId mWindowId;
  41. /**
  42. * The top view of the hierarchy.
  43. */
  44. View mRootView;
  45. IBinder mPanelParentWindowToken;
  46. Surface mSurface;
  47. boolean mHardwareAccelerated;
  48. boolean mHardwareAccelerationRequested;
  49. HardwareRenderer mHardwareRenderer;
  50. boolean mScreenOn;
  51. /**
  52. * Scale factor used by the compatibility mode
  53. */
  54. float mApplicationScale;
  55. /**
  56. * Indicates whether the application is in compatibility mode
  57. */
  58. boolean mScalingRequired;
  59. /**
  60. * If set, ViewRootImpl doesn‘t use its lame animation for when the window resizes.
  61. */
  62. boolean mTurnOffWindowResizeAnim;
  63. /**
  64. * Left position of this view‘s window
  65. */
  66. int mWindowLeft;
  67. /**
  68. * Top position of this view‘s window
  69. */
  70. int mWindowTop;
  71. /**
  72. * Indicates whether views need to use 32-bit drawing caches
  73. */
  74. boolean mUse32BitDrawingCache;
  75. /**
  76. * For windows that are full-screen but using insets to layout inside
  77. * of the screen areas, these are the current insets to appear inside
  78. * the overscan area of the display.
  79. */
  80. final Rect mOverscanInsets = new Rect();
  81. /**
  82. * For windows that are full-screen but using insets to layout inside
  83. * of the screen decorations, these are the current insets for the
  84. * content of the window.
  85. */
  86. final Rect mContentInsets = new Rect();
  87. /**
  88. * For windows that are full-screen but using insets to layout inside
  89. * of the screen decorations, these are the current insets for the
  90. * actual visible parts of the window.
  91. */
  92. final Rect mVisibleInsets = new Rect();
  93. /**
  94. * The internal insets given by this window. This value is
  95. * supplied by the client (through
  96. * [email protected] ViewTreeObserver.OnComputeInternalInsetsListener}) and will
  97. * be given to the window manager when changed to be used in laying
  98. * out windows behind it.
  99. */
  100. final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets
  101. = new ViewTreeObserver.InternalInsetsInfo();
  102. /**
  103. * Set to true when mGivenInternalInsets is non-empty.
  104. */
  105. boolean mHasNonEmptyGivenInternalInsets;
  106. /**
  107. * All views in the window‘s hierarchy that serve as scroll containers,
  108. * used to determine if the window can be resized or must be panned
  109. * to adjust for a soft input area.
  110. */
  111. final ArrayList<View> mScrollContainers = new ArrayList<View>();
  112. final KeyEvent.DispatcherState mKeyDispatchState
  113. = new KeyEvent.DispatcherState();
  114. /**
  115. * Indicates whether the view‘s window currently has the focus.
  116. */
  117. boolean mHasWindowFocus;
  118. /**
  119. * The current visibility of the window.
  120. */
  121. int mWindowVisibility;
  122. /**
  123. * Indicates the time at which drawing started to occur.
  124. */
  125. long mDrawingTime;
  126. /**
  127. * Indicates whether or not ignoring the DIRTY_MASK flags.
  128. */
  129. boolean mIgnoreDirtyState;
  130. /**
  131. * This flag tracks when the mIgnoreDirtyState flag is set during draw(),
  132. * to avoid clearing that flag prematurely.
  133. */
  134. boolean mSetIgnoreDirtyState = false;
  135. /**
  136. * Indicates whether the view‘s window is currently in touch mode.
  137. */
  138. boolean mInTouchMode;
  139. /**
  140. * Indicates that ViewAncestor should trigger a global layout change
  141. * the next time it performs a traversal
  142. */
  143. boolean mRecomputeGlobalAttributes;
  144. /**
  145. * Always report new attributes at next traversal.
  146. */
  147. boolean mForceReportNewAttributes;
  148. /**
  149. * Set during a traveral if any views want to keep the screen on.
  150. */
  151. boolean mKeepScreenOn;
  152. /**
  153. * Bitwise-or of all of the values that views have passed to setSystemUiVisibility().
  154. */
  155. int mSystemUiVisibility;
  156. /**
  157. * Hack to force certain system UI visibility flags to be cleared.
  158. */
  159. int mDisabledSystemUiVisibility;
  160. /**
  161. * Last global system UI visibility reported by the window manager.
  162. */
  163. int mGlobalSystemUiVisibility;
  164. /**
  165. * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener
  166. * attached.
  167. */
  168. boolean mHasSystemUiListeners;
  169. /**
  170. * Set if the window has requested to extend into the overscan region
  171. * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN.
  172. */
  173. boolean mOverscanRequested;
  174. /**
  175. * Set if the visibility of any views has changed.
  176. */
  177. boolean mViewVisibilityChanged;
  178. /**
  179. * Set to true if a view has been scrolled.
  180. */
  181. boolean mViewScrollChanged;
  182. /**
  183. * Global to the view hierarchy used as a temporary for dealing with
  184. * x/y points in the transparent region computations.
  185. */
  186. final int[] mTransparentLocation = new int[2];
  187. /**
  188. * Global to the view hierarchy used as a temporary for dealing with
  189. * x/y points in the ViewGroup.invalidateChild implementation.
  190. */
  191. final int[] mInvalidateChildLocation = new int[2];
  192. /**
  193. * Global to the view hierarchy used as a temporary for dealing with
  194. * x/y location when view is transformed.
  195. */
  196. final float[] mTmpTransformLocation = new float[2];
  197. /**
  198. * The view tree observer used to dispatch global events like
  199. * layout, pre-draw, touch mode change, etc.
  200. */
  201. final ViewTreeObserver mTreeObserver = new ViewTreeObserver();
  202. /**
  203. * A Canvas used by the view hierarchy to perform bitmap caching.
  204. */
  205. Canvas mCanvas;
  206. /**
  207. * The view root impl.
  208. */
  209. final ViewRootImpl mViewRootImpl;
  210. /**
  211. * A Handler supplied by a view‘s [email protected] android.view.ViewRootImpl}. This
  212. * handler can be used to pump events in the UI events queue.
  213. */
  214. final Handler mHandler;
  215. /**
  216. * Temporary for use in computing invalidate rectangles while
  217. * calling up the hierarchy.
  218. */
  219. final Rect mTmpInvalRect = new Rect();
  220. /**
  221. * Temporary for use in computing hit areas with transformed views
  222. */
  223. final RectF mTmpTransformRect = new RectF();
  224. /**
  225. * Temporary for use in transforming invalidation rect
  226. */
  227. final Matrix mTmpMatrix = new Matrix();
  228. /**
  229. * Temporary for use in transforming invalidation rect
  230. */
  231. final Transformation mTmpTransformation = new Transformation();
  232. /**
  233. * Temporary list for use in collecting focusable descendents of a view.
  234. */
  235. final ArrayList<View> mTempArrayList = new ArrayList<View>(24);
  236. /**
  237. * The id of the window for accessibility purposes.
  238. */
  239. int mAccessibilityWindowId = View.NO_ID;
  240. /**
  241. * Flags related to accessibility processing.
  242. *
  243. * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
  244. * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS
  245. */
  246. int mAccessibilityFetchFlags;
  247. /**
  248. * The drawable for highlighting accessibility focus.
  249. */
  250. Drawable mAccessibilityFocusDrawable;
  251. /**
  252. * Show where the margins, bounds and layout bounds are for each view.
  253. */
  254. boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false);
  255. /**
  256. * Point used to compute visible regions.
  257. */
  258. final Point mPoint = new Point();
  259. /**
  260. * Used to track which View originated a requestLayout() call, used when
  261. * requestLayout() is called during layout.
  262. */
  263. View mViewRequestingLayout;
  264. /**
  265. * Creates a new set of attachment information with the specified
  266. * events handler and thread.
  267. *
  268. * @param handler the events handler the view must use
  269. */
  270. AttachInfo(IWindowSession session, IWindow window, Display display,
  271. ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {
  272. mSession = session;
  273. mWindow = window;
  274. mWindowToken = window.asBinder();
  275. mDisplay = display;
  276. mViewRootImpl = viewRootImpl;
  277. mHandler = handler;
  278. mRootCallbacks = effectPlayer;
  279. }
  280. }

首先是聲明了回調接口類:callBacks 這個類第一個是playSoundEffect ,這個用於播放按鍵聲音,參數是這個點擊事件的類型,可以看SoundEffectConstants中的聲明,一般是SoundEffectConstants中幾個常量中的一個,在AttachInfo有一個CallBack對象 :mRootCallBacks 這個的實現可以看ViewRootImpl類,ViewRootImpl中,我們可以看到:

[java] view plain copy 技術分享技術分享
  1. public void playSoundEffect(int effectId) {
  2. checkThread();
  3. if (mMediaDisabled) {
  4. return;
  5. }
  6. try {
  7. final AudioManager audioManager = getAudioManager();
  8. switch (effectId) {
  9. case SoundEffectConstants.CLICK:
  10. audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
  11. return;
  12. case SoundEffectConstants.NAVIGATION_DOWN:
  13. audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
  14. return;
  15. case SoundEffectConstants.NAVIGATION_LEFT:
  16. audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
  17. return;
  18. case SoundEffectConstants.NAVIGATION_RIGHT:
  19. audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
  20. return;
  21. case SoundEffectConstants.NAVIGATION_UP:
  22. audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
  23. return;
  24. default:
  25. throw new IllegalArgumentException("unknown effect id " + effectId +
  26. " not defined in " + SoundEffectConstants.class.getCanonicalName());
  27. }
  28. } catch (IllegalStateException e) {
  29. // Exception thrown by getAudioManager() when mView is null
  30. Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
  31. e.printStackTrace();
  32. }
  33. }
那麽我們在自定義的View上,重寫playSoundEffect方法就可以了。每一個View都有playSoundEffect方法,我們可以改動這個方法。 CallBack中還有一個方法: performHapticFeedback這個意思就是觸感反饋,參數可以看HapticFeedBack這個類,當用戶在系統打開觸感反饋選項,我們View的performHapticFeedback(int feedBackContants )這個方法,當然,如果我們調用performHapticFeedback(int feedbackConstant, int flags) 的時候,把參數FLAG_IGNORE_GLOBAL_SETTING 就可以忽略全局設置,而如果我們HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING 就可以忽略我們在View裏面設置的android:hapticFeedbackEnabled 關於CallBack就講到這裏,接下來我們繼續往下看InvalidateInfo。InvalidateInfo用於刷新UI,當我們刷新UI的時候,會生成一個新的InvalidateInfo對象,然後根據這個來刷新UI。這個比較簡單,就不詳細說了。 在AttachInfo中,還有其他的信息,在這邊,我們可以拿到和Window相關的信息: [java] view plain copy 技術分享技術分享
  1. <span style="white-space:pre"> </span>final IWindowSession mSession;
  2. <span style="white-space:pre"> </span>
  3. final IWindow mWindow;
  4. final IBinder mWindowToken;
  5. IBinder mPanelParentWindowToken ;

一般來說,IWinodwSession是通過:WindowManagerGlobal.peekWindowSession() 或者是WindowManagerGlobal.getWindowSession() 來獲取的 兩者一般來說是差不多的,就是peek返回的可能為空 get一般返回是不為空的。另外,IWindowSession 、IWindow 、mWindowToken 都是從IWindowManager.Stub.asInterface(ServiceManager.getService("window"))獲取到IWindowManager來獲取的。 相關的可以看前面的第10篇:Binder進階:系統服務中的Binder 以及ServiceManager的源碼來看。 mPanelParentWindowToken 如果該窗口時子窗口,那麽該值就是父窗口的W對象,如果mWindowToken不為空,則說明沒有父窗口…嗯,和mWindowToken有點相對的意思。比如說Activity 的DecorView 的AttachInfo這個值就是null,而我們彈出了一個對話框,這個對話框的這個就不為null,因為這個對話框是有父窗口的。

017.View與窗口:AttachInfo