每一个View都需要依赖于窗口来显示,而View和窗口的关系则是放在View.AttachInfo中,关于View.AttachInfo的文章少,因为这个是View的内部类而且不是公共的,在应用层用的很少,只有在ViewRootImpl等类中才用到了,不过我觉得这个还是有点学习的必要,因此在这篇文章中就从源码入手学习下AttachInfo这个类。

   
AttachInfo 看到这个类名,我们就知道,他是代表着绑定的信息,View.AttachInfo
里面的信息,就是View和Window之间的信息。每一个被添加到窗口上的View我们都会看到有一个AttachInfo,比如我们看DecorView和Window的绑定,可以在ViewRootImpl#perfromTraversals方法中看到:
  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这个包中的类才用到。
  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. * {@link 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 {@link 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中,我们可以看到:

  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相关的信息:
  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的更多相关文章

  1. 使用WindowManager添加View——悬浮窗口的基本原理

    Android系统中的“窗口”类型虽然很多,但只有两大类是经常使用的:一是由系统进程管理的,称之为“系统窗口”:第二个就是由应用程序产生的,用于显示UI界面的“应用窗口”.如果大家熟悉WindowMa ...

  2. 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)

    Android 的窗口管理系统 (View, Canvas, WindowManager) 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道And ...

  3. Android 的窗口管理系统 (View, Canvas, WindowManager)

    http://blog.csdn.net/ritterliu/article/details/39295271 From漫天尘沙 在图解Android - Zygote 和 System Server ...

  4. go语言使用go-sciter创建桌面应用(七) view对象常用方法,文件选择,窗口弹出,请求

    view对象的详细文档请看: https://sciter.com/docs/content/sciter/View.htm demo9.html代码如下: <!DOCTYPE html> ...

  5. 浅析 Android 的窗口

    来源:http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=555&fromuid=6   一.窗口的概念 在开发过程中,我们经常会 ...

  6. 浅析Android的窗口

    一.窗口的概念 在开发过程中,我们经常会遇到,各种跟窗口相关的类,或者方法.但是,在 Android 的框架设计中,到底什么是窗口?窗口跟 Android Framework 中的 Window 类又 ...

  7. Android10_原理机制系列_Activity窗口添加到WMS过程

    前言 首先看一个Android界面的布局层次结构,最直观的看一下: 我们能清晰看到,这个界面分成了3部分:顶部状态栏(statusbar).底部导航栏(navigationbar).应用界面. 题外话 ...

  8. Android 浮窗开发之窗口层级

    很多人都知道如何去实现一个简单的浮窗,但是却很少有人去深入的研究背后的流程机制,由于项目中浮窗交互比较复杂,遇到了些坑查看了很多资料,故总结浮窗涉及到的知识点: 窗口层级关系(浮窗是如何"浮 ...

  9. iOS开发——UI进阶篇(八)pickerView简单使用,通过storyboard加载控制器,注册界面,通过xib创建控制器,控制器的view创建,导航控制器的基本使用

    一.pickerView简单使用 1.UIPickerViewDataSource 这两个方法必须实现 // 返回有多少列 - (NSInteger)numberOfComponentsInPicke ...

随机推荐

  1. Python虚拟机函数机制之参数类别(三)

    参数类别 我们在Python虚拟机函数机制之无参调用(一)和Python虚拟机函数机制之名字空间(二)这两个章节中,分别PyFunctionObject对象和函数执行时的名字空间.本章,我们来剖析一下 ...

  2. Linux的档案权限与目录配置

    重点回顾:1.Linux的每个档案中,依据权限分为使用者.群组与其他人三种身份 2.群组最有用的功能之一,就是当你在团队开发资源的时候,且每个账号都可以有多个群组的支持 3.利用"ls -l ...

  3. 06-python进阶-多线程下载器练手

    我们需要用python 写一个多线程的下载器 我们要先获取这个文件的大小 然后将其分片 然后启动多线程 分别去下载 然后将其拼接起来 #!/usr/bin/env python#coding:utf- ...

  4. python补漏----isinstance 和 issubclass

    一.isinstance Python 中的isinstance函数 isinstance是Python中的一个内建函数 语法: isinstance(object, classinfo) 如果参数o ...

  5. 如何用jquery+json来写页面

    以下是json数据表: [ { "p" : "银川市", "c" : [{"c1":"兴庆区"},{ ...

  6. hibernate缓存详解

    hibernate中提供了两级缓存,一级缓存是Session级别的缓存,它属于事务范围的缓存,该级缓存由hibernate管理,应用程序无需干预:二级缓存是SessionFactory级别的缓存,该级 ...

  7. Java容器jdk1.6 Array

    参考:https://www.cnblogs.com/tstd/p/5042087.html 1.定义 顶层接口collection public interface Collection<E& ...

  8. JavaScriptCore 简介

    转自http://esoftmobile.com/2013/06/19/integrating-javascript-into-native-applications/ Integrating Jav ...

  9. webstorm自带debugger服务器

    打开webstorm->settings->Build,Execution,Deployment->Debugger->把端口Port改成8089或者其他80端口,按确定就可以 ...

  10. 周赛Problem 1021: 分蛋糕(埃拉托斯特尼筛法)

    Problem 1021: 分蛋糕 Time Limits:  1000 MS   Memory Limits:  65536 KB 64-bit interger IO format:  %lld  ...