标签:fetch oba adjust create pop net cal argument forms
每一个View都需要依赖于窗口来显示,而View和窗口的关系则是放在View.AttachInfo中,关于View.AttachInfo的文章少,因为这个是View的内部类而且不是公共的,在应用层用的很少,只有在ViewRootImpl等类中才用到了,不过我觉得这个还是有点学习的必要,因此在这篇文章中就从源码入手学习下AttachInfo这个类。
AttachInfo 看到这个类名,我们就知道,他是代表着绑定的信息,View.AttachInfo
里面的信息,就是View和Window之间的信息。每一个被添加到窗口上的View我们都会看到有一个AttachInfo,比如我们看DecorView和Window的绑定,可以在ViewRootImpl#perfromTraversals方法中看到:
- final View.AttachInfo attachInfo = mAttachInfo;
-
- final int viewVisibility = getHostVisibility();
- boolean viewVisibilityChanged = mViewVisibility != viewVisibility
- || mNewSurfaceNeeded;
-
- WindowManager.LayoutParams params = null;
- if (mWindowAttributesChanged) {
- mWindowAttributesChanged = false;
- surfaceChanged = true;
- params = lp;
- }
- CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
- if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
- params = lp;
- mFullRedrawNeeded = true;
- mLayoutRequested = true;
- if (mLastInCompatMode) {
- params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
- mLastInCompatMode = false;
- } else {
- params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
- mLastInCompatMode = true;
- }
- }
-
- mWindowAttributesChangesFlag = 0;
-
- Rect frame = mWinFrame;
- if (mFirst) {
- mFullRedrawNeeded = true;
- mLayoutRequested = true;
-
- if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
- || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
-
- Point size = new Point();
- mDisplay.getRealSize(size);
- desiredWindowWidth = size.x;
- desiredWindowHeight = size.y;
- } else {
- DisplayMetrics packageMetrics =
- mView.getContext().getResources().getDisplayMetrics();
- desiredWindowWidth = packageMetrics.widthPixels;
- desiredWindowHeight = packageMetrics.heightPixels;
- }
-
-
-
-
-
- attachInfo.mSurface = mSurface;
-
-
-
- attachInfo.mUse32BitDrawingCache = true;
- attachInfo.mHasWindowFocus = false;
- attachInfo.mWindowVisibility = viewVisibility;
- attachInfo.mRecomputeGlobalAttributes = false;
- viewVisibilityChanged = false;
- mLastConfiguration.setTo(host.getResources().getConfiguration());
- mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
-
- if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
- host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
- }
- host.dispatchAttachedToWindow(attachInfo, 0);
-
AttachInfo 会通过View的diapatchAttachedTowWindow分发给View。如果是一个ViewGroup 那么这个这个AttachInfo也会分发给所有子View,以引用的方式。
下面我们可以看下AttachInfo这个类,这个类是View的内部类,不是声明为public的,所以只有view这个包中的类才用到。
首先是声明了回调接口类:callBacks 这个类第一个是playSoundEffect ,这个用于播放按键声音,参数是这个点击事件的类型,可以看SoundEffectConstants中的声明,一般是SoundEffectConstants中几个常量中的一个,在AttachInfo有一个CallBack对象
:mRootCallBacks 这个的实现可以看ViewRootImpl类,ViewRootImpl中,我们可以看到:
- public void playSoundEffect(int effectId) {
- checkThread();
-
- if (mMediaDisabled) {
- return;
- }
-
- try {
- final AudioManager audioManager = getAudioManager();
-
- switch (effectId) {
- case SoundEffectConstants.CLICK:
- audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
- return;
- case SoundEffectConstants.NAVIGATION_DOWN:
- audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_DOWN);
- return;
- case SoundEffectConstants.NAVIGATION_LEFT:
- audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_LEFT);
- return;
- case SoundEffectConstants.NAVIGATION_RIGHT:
- audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_RIGHT);
- return;
- case SoundEffectConstants.NAVIGATION_UP:
- audioManager.playSoundEffect(AudioManager.FX_FOCUS_NAVIGATION_UP);
- return;
- default:
- throw new IllegalArgumentException("unknown effect id " + effectId +
- " not defined in " + SoundEffectConstants.class.getCanonicalName());
- }
- } catch (IllegalStateException e) {
-
- Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
- e.printStackTrace();
- }
- }
那么我们在自定义的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相关的信息:
- <span style="white-space:pre"> </span>final IWindowSession mSession;
- <span style="white-space:pre"> </span>
- final IWindow mWindow;
-
- final IBinder mWindowToken;
- 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
标签:fetch oba adjust create pop net cal argument forms
原文地址:http://www.cnblogs.com/ldq2016/p/6835187.html