• 017.View与窗口:AttachInfo


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


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

    首先是声明了回调接口类:callBacks 这个类第一个是playSoundEffect ,这个用于播放按键声音,参数是这个点击事件的类型,可以看SoundEffectConstants中的声明,一般是SoundEffectConstants中几个常量中的一个,在AttachInfo有一个CallBack对象 :mRootCallBacks 这个的实现可以看ViewRootImpl类,ViewRootImpl中,我们可以看到:

    1. public void playSoundEffect(int effectId) {  
    2.       checkThread();  
    3.   
    4.       if (mMediaDisabled) {  
    5.           return;  
    6.       }  
    7.   
    8.       try {  
    9.           final AudioManager audioManager = getAudioManager();  
    10.   
    11.           switch (effectId) {  
    12.               case SoundEffectConstants.CLICK:  
    13.                   audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);  
    14.                   return;  
    15.               case SoundEffectConstants.NAVIGATION_DOWN:  
    16.                   audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);  
    17.                   return;  
    18.               case SoundEffectConstants.NAVIGATION_LEFT:  
    19.                   audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);  
    20.                   return;  
    21.               case SoundEffectConstants.NAVIGATION_RIGHT:  
    22.                   audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);  
    23.                   return;  
    24.               case SoundEffectConstants.NAVIGATION_UP:  
    25.                   audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);  
    26.                   return;  
    27.               default:  
    28.                   throw new IllegalArgumentException("unknown effect id " + effectId +  
    29.                           " not defined in " + SoundEffectConstants.class.getCanonicalName());  
    30.           }  
    31.       } catch (IllegalStateException e) {  
    32.           // Exception thrown by getAudioManager() when mView is null  
    33.           Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);  
    34.           e.printStackTrace();  
    35.       }  
    36.   }  
    那么我们在自定义的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.   
    5.         final IBinder mWindowToken;  
    6.         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,因为这个对话框是有父窗口的。


  • 相关阅读:
    C#Type类中的IsAssignableFrom、IsInstanceOfType、IsSubclassOf
    C# IsAssignableFrom & IsInstanceOfType & IsSubclassOf & Is
    VS2017桌面应用程序打包成.msi或者.exe
    C# 10个常用特性
    ADO.NET 的六大对象及其关系图
    Expression表达式树(C#)
    表达式树 Expression Trees
    特性 Attribute
    C# 特性(attribute)
    Vue中使用axios
  • 原文地址:https://www.cnblogs.com/ldq2016/p/6835187.html
Copyright © 2020-2023  润新知