美文网首页安卓Android弹窗
FrameWork层源码分析之dialog

FrameWork层源码分析之dialog

作者: 暴走的小青春 | 来源:发表于2019-11-10 15:57 被阅读0次

    popwindow和dialog相信大家在开发过程中已经用的很多了,但是很多人对其中的机制以及两者间的区别不甚了解,在谈论之前,先说几个问题
    1.popwindow和dialog都能在activity的oncreate中show么?
    2.popwindow和dialog都是子窗口类型么?
    3.dialog和popwindow的共同点和区别点?
    要明确的回答这三个问题,必须要在这两个类的源码中找答案了

    这篇文章先来说下dialog

    dialog的初始化代码如下

      Dialog dialog = new Dialog(this);
      dialog.setContentView(R.layout.dialog_test);
      dialog.show();
    

    可以看到这里new了一个dialog参数必须是所依附的activity的context,
    那application的context可以么?去看下它的构造参数把

      //关键点1
      if (createContextThemeWrapper) {
                if (themeResId == ResourceId.ID_NULL) {
                    final TypedValue outValue = new TypedValue();
                    context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
                    themeResId = outValue.resourceId;
                }
                mContext = new ContextThemeWrapper(context, themeResId);
            } else {
                mContext = context;
            }
           //关键点2
            mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
           //关键点3
            final Window w = new PhoneWindow(mContext);
            mWindow = w;
          //关键点4
            w.setCallback(this);
            w.setOnWindowDismissedCallback(this);
            w.setOnWindowSwipeDismissedCallback(() -> {
                if (mCancelable) {
                    cancel();
                }
            });
           //关键点5
            w.setWindowManager(mWindowManager, null, null);
            w.setGravity(Gravity.CENTER);
    
            mListenersHandler = new ListenersHandler(this);
    

    这里有几个点很明确:
    1.dialog可以用自带的主题,如果外面设置进来就用外面的主题
    2.就是获取了mWindowManager的对象,大家都知道,mWindowManager相当于管家,添加,移除,和更改window都是通过
    mWindowManager来操作的,显然看WindowManager的源码得知里面包含了window一系列的信息

    /**
             * Identifier for this window.  This will usually be filled in for
             * you.
             */
            public IBinder token = null;
    
            /**
             * Name of the package owning this window.
             */
            public String packageName = null;
    
            public static final int TYPE_APPLICATION_STARTING = 3;
    
            /**
             * Window type: a variation on TYPE_APPLICATION that ensures the window
             * manager will wait for this window to be drawn before the app is shown.
             * In multiuser systems shows only on the owning user's window.
             */
            public static final int TYPE_DRAWN_APPLICATION = 4;
    
            /**
             * End of types of application windows.
             */
            public static final int LAST_APPLICATION_WINDOW = 99;
    
            /**
             * Start of types of sub-windows.  The {@link #token} of these windows
             * must be set to the window they are attached to.  These types of
             * windows are kept next to their attached window in Z-order, and their
             * coordinate space is relative to their attached window.
             */
            public static final int FIRST_SUB_WINDOW = 1000;
    
    

    包括了此window的token,类型,所在的包名,还有一些属性参数等都包括在了里面
    那如果用了context的所属activity的话,这些参数包含的都是activity里面创建出来window的信息了
    3.创建了phonewindow以前我一直误认为创建了phonewindow就是有个新的window,没有创建就没有window,其实不然,phonewindow里只是对DecorView的创建,以及对一些window的属性初始化罢了
    比如这个window是否是悬浮的,大小,动画等
    4.这里设置了一个window的回调用,是关于事件的分发的,过会再说
    5.这里用window绑定了windowmanager
    这个方法注意是为此window绑定了一个它的windowmanager(其实没啥用,后面会说)
    在初始化之后,把布局放进了window的contentview以后就调用了show方法

    public void show() {
            if (mShowing) {
                if (mDecor != null) {
                    if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                        mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
                    }
                    mDecor.setVisibility(View.VISIBLE);
                }
                return;
            }
    
            mCanceled = false;
    
            if (!mCreated) {
                dispatchOnCreate(null);
            } else {
                // Fill the DecorView in on any configuration changes that
                // may have occured while it was removed from the WindowManager.
                final Configuration config = mContext.getResources().getConfiguration();
                mWindow.getDecorView().dispatchConfigurationChanged(config);
            }
    
            onStart();
            mDecor = mWindow.getDecorView();
    
            if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                final ApplicationInfo info = mContext.getApplicationInfo();
                mWindow.setDefaultIcon(info.icon);
                mWindow.setDefaultLogo(info.logo);
                mActionBar = new WindowDecorActionBar(this);
            }
    
            WindowManager.LayoutParams l = mWindow.getAttributes();
            boolean restoreSoftInputMode = false;
            if ((l.softInputMode
                    & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
                l.softInputMode |=
                        WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
                restoreSoftInputMode = true;
            }
           //关键点1
            mWindowManager.addView(mDecor, l);
            if (restoreSoftInputMode) {
                l.softInputMode &=
                        ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
            }
    
            mShowing = true;
    
            sendShowMessage();
        }
    

    这里关键点1便是windowmanager.addview的方法了,此方法会调用windowmanagerImp的addview方法

     @Override
        public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
            applyDefaultToken(params);
            mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
        }
    

    这里的mParentWindow其实就是依附的activity的window,和自身的window其实没有关系,紧接着调用了WindowManagerGlobal的addview方法

     public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
            if (view == null) {
                throw new IllegalArgumentException("view must not be null");
            }
            if (display == null) {
                throw new IllegalArgumentException("display must not be null");
            }
            if (!(params instanceof WindowManager.LayoutParams)) {
                throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
            }
    
            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
            if (parentWindow != null) {
               //关键点1
                parentWindow.adjustLayoutParamsForSubWindow(wparams);
            } else {
                // If there's no parent, then hardware acceleration for this view is
                // set from the application's hardware acceleration setting.
                final Context context = view.getContext();
                if (context != null
                        && (context.getApplicationInfo().flags
                                & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                    wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
                }
            }
    
            ViewRootImpl root;
            View panelParentView = null;
    
            synchronized (mLock) {
                // Start watching for system property changes.
                if (mSystemPropertyUpdater == null) {
                    mSystemPropertyUpdater = new Runnable() {
                        @Override public void run() {
                            synchronized (mLock) {
                                for (int i = mRoots.size() - 1; i >= 0; --i) {
                                    mRoots.get(i).loadSystemProperties();
                                }
                            }
                        }
                    };
                    SystemProperties.addChangeCallback(mSystemPropertyUpdater);
                }
    
                int index = findViewLocked(view, false);
                if (index >= 0) {
                    if (mDyingViews.contains(view)) {
                        // Don't wait for MSG_DIE to make it's way through root's queue.
                        mRoots.get(index).doDie();
                    } else {
                        throw new IllegalStateException("View " + view
                                + " has already been added to the window manager.");
                    }
                    // The previous removeView() had not completed executing. Now it has.
                }
    
                // If this is a panel window, then find the window it is being
                // attached to for future reference.
         //关键点2
                if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                        wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                    final int count = mViews.size();
                    for (int i = 0; i < count; i++) {
                        if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                            panelParentView = mViews.get(i);
                        }
                    }
                }
               //关键点3
                root = new ViewRootImpl(view.getContext(), display);
    
                view.setLayoutParams(wparams);
    
                mViews.add(view);
                mRoots.add(root);
                mParams.add(wparams);
    
                // do this last because it fires off messages to start doing things
                try {
            //关键点4
                    root.setView(view, wparams, panelParentView);
                } catch (RuntimeException e) {
                    // BadTokenException or InvalidDisplayException, clean up.
                    if (index >= 0) {
                        removeViewLocked(index, true);
                    }
                    throw e;
                }
            }
        }
    

    这里有四个关键点
    1.会调用parentWindow .adjustLayoutParamsForSubWindow这个方法

    void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
            CharSequence curTitle = wp.getTitle();
            if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                if (wp.token == null) {
                    View decor = peekDecorView();
                    if (decor != null) {
                        wp.token = decor.getWindowToken();
                    }
                }
                if (curTitle == null || curTitle.length() == 0) {
                    final StringBuilder title = new StringBuilder(32);
                    if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA) {
                        title.append("Media");
                    } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY) {
                        title.append("MediaOvr");
                    } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
                        title.append("Panel");
                    } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL) {
                        title.append("SubPanel");
                    } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL) {
                        title.append("AboveSubPanel");
                    } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG) {
                        title.append("AtchDlg");
                    } else {
                        title.append(wp.type);
                    }
                    if (mAppName != null) {
                        title.append(":").append(mAppName);
                    }
                    wp.setTitle(title);
                }
            } else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
                    wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
                // We don't set the app token to this system window because the life cycles should be
                // independent. If an app creates a system window and then the app goes to the stopped
                // state, the system window should not be affected (can still show and receive input
                // events).
                if (curTitle == null || curTitle.length() == 0) {
                    final StringBuilder title = new StringBuilder(32);
                    title.append("Sys").append(wp.type);
                    if (mAppName != null) {
                        title.append(":").append(mAppName);
                    }
                    wp.setTitle(title);
                }
            } else {
                if (wp.token == null) {
    //关键点1.1
                    wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
                }
                if ((curTitle == null || curTitle.length() == 0)
                        && mAppName != null) {
                    wp.setTitle(mAppName);
                }
            }
            if (wp.packageName == null) {
                wp.packageName = mContext.getPackageName();
            }
            if (mHardwareAccelerated ||
                    (mWindowAttributes.flags & FLAG_HARDWARE_ACCELERATED) != 0) {
                wp.flags |= FLAG_HARDWARE_ACCELERATED;
            }
        }
    

    关键点1.1
    这方法就给这个window设置token的,我们可以看到由于在dialog中用了phonewindow所以,window的类型就是应用窗口了,也就走到了else里了所以是在这里设置的token的,popwindow后文会说
    关键点2
    也就是非应用窗口赋值panelParentView的地方,与dialog其实关系不大
    关键点3
    这里新建了ViewRootImpl对象,可以这么说,每一个window都有一个
    ViewRootImpl对象,里面封装着很多东西

    public ViewRootImpl(Context context, Display display) {
            mContext = context;
            mWindowSession = WindowManagerGlobal.getWindowSession();
            mDisplay = display;
            mBasePackageName = context.getBasePackageName();
            mThread = Thread.currentThread();
            mLocation = new WindowLeaked(null);
            mLocation.fillInStackTrace();
            mWidth = -1;
            mHeight = -1;
            mDirty = new Rect();
            mTempRect = new Rect();
            mVisRect = new Rect();
            mWinFrame = new Rect();
            mWindow = new W(this);
            mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
            mViewVisibility = View.GONE;
            mTransparentRegion = new Region();
            mPreviousTransparentRegion = new Region();
            mFirst = true; // true for the first time the view is added
            mAdded = false;
            mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                    context);
            mAccessibilityManager = AccessibilityManager.getInstance(context);
            mAccessibilityManager.addAccessibilityStateChangeListener(
                    mAccessibilityInteractionConnectionManager, mHandler);
            mHighContrastTextManager = new HighContrastTextManager();
            mAccessibilityManager.addHighTextContrastStateChangeListener(
                    mHighContrastTextManager, mHandler);
            mViewConfiguration = ViewConfiguration.get(context);
            mDensity = context.getResources().getDisplayMetrics().densityDpi;
            mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
            mFallbackEventHandler = new PhoneFallbackEventHandler(context);
            mChoreographer = Choreographer.getInstance();
            mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
    
            if (!sCompatibilityDone) {
                sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P;
    
                sCompatibilityDone = true;
            }
    
            loadSystemProperties();
        }
    

    可以看到,里面初始化了windowSession,这个进行IPC的时候会用到,还有mAttachInfo对象,是view和viewImp的桥梁包括还有mChoreographer对象是屏幕刷新的对象,顺便说一句,view.post时,执行的时机,就是有了这个mAttachInfo才放到消息队列等待执行的
    在看下关键点四
    也是最重要的方法,走到了viewRootImp的setView方法

     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
            synchronized (this) {
                if (mView == null) {
                    mView = view;
    
                    mAttachInfo.mDisplayState = mDisplay.getState();
                    mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
    
                    mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
                    mFallbackEventHandler.setView(view);
                    mWindowAttributes.copyFrom(attrs);
                    if (mWindowAttributes.packageName == null) {
                        mWindowAttributes.packageName = mBasePackageName;
                    }
                    attrs = mWindowAttributes;
                    setTag();
    
                    if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
                            & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
                            && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
                        Slog.d(mTag, "setView: FLAG_KEEP_SCREEN_ON changed from true to false!");
                    }
                    // Keep track of the actual window flags supplied by the client.
                    mClientWindowLayoutFlags = attrs.flags;
    
                    setAccessibilityFocus(null, null);
    
                    if (view instanceof RootViewSurfaceTaker) {
                        mSurfaceHolderCallback =
                                ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
                        if (mSurfaceHolderCallback != null) {
                            mSurfaceHolder = new TakenSurfaceHolder();
                            mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
                            mSurfaceHolder.addCallback(mSurfaceHolderCallback);
                        }
                    }
    
                    // Compute surface insets required to draw at specified Z value.
                    // TODO: Use real shadow insets for a constant max Z.
                    if (!attrs.hasManualSurfaceInsets) {
                        attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
                    }
    
                    CompatibilityInfo compatibilityInfo =
                            mDisplay.getDisplayAdjustments().getCompatibilityInfo();
                    mTranslator = compatibilityInfo.getTranslator();
    
                    // If the application owns the surface, don't enable hardware acceleration
                    if (mSurfaceHolder == null) {
                        // While this is supposed to enable only, it can effectively disable
                        // the acceleration too.
                        enableHardwareAcceleration(attrs);
                        final boolean useMTRenderer = MT_RENDERER_AVAILABLE
                                && mAttachInfo.mThreadedRenderer != null;
                        if (mUseMTRenderer != useMTRenderer) {
                            // Shouldn't be resizing, as it's done only in window setup,
                            // but end just in case.
                            endDragResizing();
                            mUseMTRenderer = useMTRenderer;
                        }
                    }
    
                    boolean restore = false;
                    if (mTranslator != null) {
                        mSurface.setCompatibilityTranslator(mTranslator);
                        restore = true;
                        attrs.backup();
                        mTranslator.translateWindowLayout(attrs);
                    }
                    if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);
    
                    if (!compatibilityInfo.supportsScreen()) {
                        attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
                        mLastInCompatMode = true;
                    }
    
                    mSoftInputMode = attrs.softInputMode;
                    mWindowAttributesChanged = true;
                    mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;
                    mAttachInfo.mRootView = view;
                    mAttachInfo.mScalingRequired = mTranslator != null;
                    mAttachInfo.mApplicationScale =
                            mTranslator == null ? 1.0f : mTranslator.applicationScale;
                    if (panelParentView != null) {
                        mAttachInfo.mPanelParentWindowToken
                                = panelParentView.getApplicationWindowToken();
                    }
                    mAdded = true;
                    int res; /* = WindowManagerImpl.ADD_OKAY; */
    
                    // 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.
                   //关键点一
                    requestLayout();
                    if ((mWindowAttributes.inputFeatures
                            & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                        mInputChannel = new InputChannel();
                    }
                    mForceDecorViewVisibility = (mWindowAttributes.privateFlags
                            & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
                    try {
                        mOrigWindowType = mWindowAttributes.type;
                        mAttachInfo.mRecomputeGlobalAttributes = true;
                        collectViewAttributes();
     //关键点二
                        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                                getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
                                mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                                mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
                    } catch (RemoteException e) {
                        mAdded = false;
                        mView = null;
                        mAttachInfo.mRootView = null;
                        mInputChannel = null;
                        mFallbackEventHandler.setView(null);
                        unscheduleTraversals();
                        setAccessibilityFocus(null, null);
                        throw new RuntimeException("Adding window failed", e);
                    } finally {
                        if (restore) {
                            attrs.restore();
                        }
                    }
    
                    if (mTranslator != null) {
                        mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
                    }
                    mPendingOverscanInsets.set(0, 0, 0, 0);
                    mPendingContentInsets.set(mAttachInfo.mContentInsets);
                    mPendingStableInsets.set(mAttachInfo.mStableInsets);
                    mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
                    mPendingVisibleInsets.set(0, 0, 0, 0);
                    mAttachInfo.mAlwaysConsumeNavBar =
                            (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR) != 0;
                    mPendingAlwaysConsumeNavBar = mAttachInfo.mAlwaysConsumeNavBar;
                    if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
                    if (res < WindowManagerGlobal.ADD_OKAY) {
                        mAttachInfo.mRootView = null;
                        mAdded = false;
                        mFallbackEventHandler.setView(null);
                        unscheduleTraversals();
                        setAccessibilityFocus(null, null);
                        switch (res) {
                            case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
                            case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
                                throw new WindowManager.BadTokenException(
                                        "Unable to add window -- token " + attrs.token
                                        + " is not valid; is your activity running?");
                            case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
                                throw new WindowManager.BadTokenException(
                                        "Unable to add window -- token " + attrs.token
                                        + " is not for an application");
                            case WindowManagerGlobal.ADD_APP_EXITING:
                                throw new WindowManager.BadTokenException(
                                        "Unable to add window -- app for token " + attrs.token
                                        + " is exiting");
                            case WindowManagerGlobal.ADD_DUPLICATE_ADD:
                                throw new WindowManager.BadTokenException(
                                        "Unable to add window -- window " + mWindow
                                        + " has already been added");
                            case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
                                // Silently ignore -- we would have just removed it
                                // right away, anyway.
                                return;
                            case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
                                throw new WindowManager.BadTokenException("Unable to add window "
                                        + mWindow + " -- another window of type "
                                        + mWindowAttributes.type + " already exists");
                            case WindowManagerGlobal.ADD_PERMISSION_DENIED:
                                throw new WindowManager.BadTokenException("Unable to add window "
                                        + mWindow + " -- permission denied for window type "
                                        + mWindowAttributes.type);
                            case WindowManagerGlobal.ADD_INVALID_DISPLAY:
                                throw new WindowManager.InvalidDisplayException("Unable to add window "
                                        + mWindow + " -- the specified display can not be found");
                            case WindowManagerGlobal.ADD_INVALID_TYPE:
                                throw new WindowManager.InvalidDisplayException("Unable to add window "
                                        + mWindow + " -- the specified window type "
                                        + mWindowAttributes.type + " is not valid");
                        }
                        throw new RuntimeException(
                                "Unable to add window -- unknown error code " + res);
                    }
    
                    if (view instanceof RootViewSurfaceTaker) {
                        mInputQueueCallback =
                            ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
                    }
    //关键点三
                    if (mInputChannel != null) {
                        if (mInputQueueCallback != null) {
                            mInputQueue = new InputQueue();
                            mInputQueueCallback.onInputQueueCreated(mInputQueue);
                        }
                        mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                                Looper.myLooper());
                    }
    //关键点四
                    view.assignParent(this);
                    mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
                    mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
    
                    if (mAccessibilityManager.isEnabled()) {
                        mAccessibilityInteractionConnectionManager.ensureConnection();
                    }
    
                    if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
                        view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
                    }
    
                    // Set up the input pipeline.
                    CharSequence counterSuffix = attrs.getTitle();
                    mSyntheticInputStage = new SyntheticInputStage();
                    InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
                    InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                            "aq:native-post-ime:" + counterSuffix);
                    InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
                    InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                            "aq:ime:" + counterSuffix);
                    InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
                    InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                            "aq:native-pre-ime:" + counterSuffix);
    
                    mFirstInputStage = nativePreImeStage;
                    mFirstPostImeInputStage = earlyPostImeStage;
                    mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
                }
            }
        }
    

    代码比较长,分开来说

    关键点一是进行一次request也就是scheduleTraversals方法,进行第一次的测量,布局和绘制这里是一个消息队列的方法所以是要等到每16ms屏幕刷新给上层回掉的时候才会调用。

    关键点二便是对window进行一些初始化的操作了,大家有没有想过,为啥dialog这个window会浮在activity这个window上面的,还有popwindow为啥是浮在dialog和activity之上的,为啥新打开一个activity的window会覆盖原来的activity的window
    这其实都和window的layer有关,而mWindowSession.addToDisplay就是来判断这些window层级显示顺序,由于这个是WMS的方法,其实调用的就是session的addToDisplay方法,间接调用了windowmanagerservice的addwindow方法,

     public int addWindow(Session session, IWindow client, int seq,
                             LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
                             Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
                             DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
            int[] appOp = new int[1];
            int res = mPolicy.checkAddPermission(attrs, appOp);
            if (res != WindowManagerGlobal.ADD_OKAY) {
                return res;
    ......
            }
    

    这里的session是system_server进程和app进程的桥梁
    这方法具体做的事情就是验证window的有效性和新建了windowState对象,其实window具体的表现形式就是windowState,有多少windowState就是多少window(这里说的window包括了子window)
    举个例子:activity中创建的window是windowState,而dialog也是一个windowState,都是应用类型window,只不过依附的token是activity的token,插入的顺序依据的所附属的activity决定的,而popwindow也是一个windowState,只不过它是属于子window的类型,是根据mSubLayer的插入的,这个值越大,越靠前,可以看下LooperJing对于window的分析了,可以说是解析window最详细的文章了,不过是基于6.0的,现在8.0中wms代码稍有变化,本质是一样的

    在来看下关键点三,这里创建了一个mInputChannel,当然底层也是相当的复杂,以后专门抽一篇文章来说,主要作用是注册一个native事件,然后当用户触摸到屏幕了,这个native事件会给java层回调,从而进行事件的分发,其实在这里面也进行了跨进程的交互,只不过用的是socket的方法

    关键点四就比较简单了,为view设置了一个虚拟的viewparent也就是viewRootImp

    总的来说dialog的显示也就说完了,来总结一下:

    1.本质和activity的window一样,只不过它的一些属性是特定的,所以在window显示中会不一样。
    2,关于dialog的事件,由于是在activity的window之上,并且注册了事件,所以在显示的外部事件是先传给dialog的,当然有属性可以改变这个默认的规则。
    3 dialog和activity公用一个windowManager,也就是同一个token,所以在oncreate时因为windowManger已经创建了,所以dialog的token也是不为null的,可以在oncreate中show()
    4.所有dialog的动画其实就是winodow的动画,dialog也可以按照style设置不同的主题
    ps:dialog和popwindow不同于activity,activity在执行onResume后触发windowManager的add的操作,而这两个却不同

    下篇文章分析popwindow的显示,并且说下两者间的区别

    相关文章

      网友评论

        本文标题:FrameWork层源码分析之dialog

        本文链接:https://www.haomeiwen.com/subject/uvqobctx.html