Window和WindowManager(二)

作者: 大虾啊啊啊 | 来源:发表于2018-09-04 10:20 被阅读12次

Window的删除过程

上篇文章我们讲到了Window的添加过程,接下来我们来分析Window的删除过程。还是和添加一样,首先通过WindowManagerImpl这个对象调用removeView方法。

   @Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }

接着通过 WindowManagerGlobal mGlobal 对象调用removeView方法。我们来看WindowManagerGlobal 中的removeView方法:

    public void removeView(View view, boolean immediate) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }

        synchronized (mLock) {
            int index = findViewLocked(view, true);
            View curView = mRoots.get(index).getView();
            removeViewLocked(index, immediate);
            if (curView == view) {
                return;
            }

            throw new IllegalStateException("Calling with view " + view
                    + " but the ViewAncestor is attached to " + curView);
        }
    }

我们来看核心实现,首先从mViews集合获取需要删除View的索引,因为在添加View的时候,把View添加到了mViews这个集合。

    int index = findViewLocked(view, true);

    private int findViewLocked(View view, boolean required) {
        final int index = mViews.indexOf(view);
        if (required && index < 0) {
            throw new IllegalArgumentException("View=" + view + " not attached to window manager");
        }
        return index;
    }

通过索引调用removeViewLocked方法,删除该View

         removeViewLocked(index, immediate);

      private void removeViewLocked(int index, boolean immediate) {
        ViewRootImpl root = mRoots.get(index);
        View view = root.getView();

        if (view != null) {
            InputMethodManager imm = InputMethodManager.getInstance();
            if (imm != null) {
                imm.windowDismissed(mViews.get(index).getWindowToken());
            }
        }
        boolean deferred = root.die(immediate);
        if (view != null) {
            view.assignParent(null);
            if (deferred) {
                mDyingViews.add(view);
            }
        }
    }

我们看上面的源码。首先通过该View对应的索引,获取对应的ViewRootImpl类,我们知道每个Window和View多是通过ViewRootImpl建立连接的,对Window的操作,其实就是通过ViewRootImpl来操作的。每个Window都会有对应的ViewRootImpl类。拿到该View对应的ViewRootImpl也就是该Window对应的ViewRootImpl类之后,调用die方法进行删除操作。

boolean deferred = root.die(immediate);

我们来看下die方法的实现,

/**
     * @param immediate True, do now if not in traversal. False, put on queue and do later.
     * @return True, request has been queued. False, request has been completed.
     */
    boolean die(boolean immediate) {
        // Make sure we do execute immediately if we are in the middle of a traversal or the damage
        // done by dispatchDetachedFromWindow will cause havoc on return.
        if (immediate && !mIsInTraversal) {
            doDie();
            return false;
        }

        if (!mIsDrawing) {
            destroyHardwareRenderer();
        } else {
            Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
                    "  window=" + this + ", title=" + mWindowAttributes.getTitle());
        }
        mHandler.sendEmptyMessage(MSG_DIE);
        return true;
    }

在这个方法中,有一个immediate参数,表示异步删除还是同步删除,如果是同步删除,直接调用doDie()方法。如果是异步删除,发送一个消息 mHandler.sendEmptyMessage(MSG_DIE);然后调用doDiew()方法。因此,删除的核心方法都在doDie()中。我们来看下doDie()方法的实现

void doDie() {
        checkThread();
        if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
        synchronized (this) {
            if (mRemoved) {
                return;
            }
            mRemoved = true;
            if (mAdded) {
                dispatchDetachedFromWindow();
            }

            if (mAdded && !mFirst) {
                destroyHardwareRenderer();

                if (mView != null) {
                    int viewVisibility = mView.getVisibility();
                    boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
                    if (mWindowAttributesChanged || viewVisibilityChanged) {
                        // If layout params have been changed, first give them
                        // to the window manager to make sure it has the correct
                        // animation info.
                        try {
                            if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
                                    & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                                mWindowSession.finishDrawing(mWindow);
                            }
                        } catch (RemoteException e) {
                        }
                    }

                    mSurface.release();
                }
            }

            mAdded = false;
        }
        WindowManagerGlobal.getInstance().doRemoveView(this);
    }

在doDie()方法中,删除的核心实现通过 dispatchDetachedFromWindow();来完成。

void dispatchDetachedFromWindow() {
        if (mView != null && mView.mAttachInfo != null) {
            mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
            mView.dispatchDetachedFromWindow();
        }

        mAccessibilityInteractionConnectionManager.ensureNoConnection();
        mAccessibilityManager.removeAccessibilityStateChangeListener(
                mAccessibilityInteractionConnectionManager);
        mAccessibilityManager.removeHighTextContrastStateChangeListener(
                mHighContrastTextManager);
        removeSendWindowContentChangedCallback();

        destroyHardwareRenderer();

        setAccessibilityFocus(null, null);

        mView.assignParent(null);
        mView = null;
        mAttachInfo.mRootView = null;

        mSurface.release();

        if (mInputQueueCallback != null && mInputQueue != null) {
            mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
            mInputQueue.dispose();
            mInputQueueCallback = null;
            mInputQueue = null;
        }
        if (mInputEventReceiver != null) {
            mInputEventReceiver.dispose();
            mInputEventReceiver = null;
        }
        try {
            mWindowSession.remove(mWindow);
        } catch (RemoteException e) {
        }

        // Dispose the input channel after removing the window so the Window Manager
        // doesn't interpret the input channel being closed as an abnormal termination.
        if (mInputChannel != null) {
            mInputChannel.dispose();
            mInputChannel = null;
        }

        mDisplayManager.unregisterDisplayListener(mDisplayListener);

        unscheduleTraversals();
    }

在dispatchDetachedFromWindow方法中主要完成以下这些操作。
(1)调用View的dispatchDetachedFromWindow();方法,做一些资源回收的工作,比如终止动画,停止线程等。
(2)垃圾回收,比如清楚数据和消息,移除回调
(3)第三点比较重要,也是实现删除Window的真正实现, mWindowSession.remove(mWindow);在上篇文章我们知道,mWindowSession是一个Binder对象,这里是一个IPC机制,通过跨进程通信,把删除Window的操作交给了WindowManagerService进行删除。
(4)调用 WindowManagerGlobal.getInstance().doRemoveView(this);把当前保存的删除的View 列表进行移除刷新。
以上就是Window的删除大概的流程,我们做下小结:
我们知道删除Window
1.首先交给WindowManagerGlobal 的removie方法,这个方法是为了拿到需要删除的View的索引,再通过该索引拿到对应的ViewRootImpl对象,
2.然后删除Window的实现交给了ViewRootImpl来完成。通过调用die方法。
3.最后的核心删除操作就是和添加Window类似,通过Binde对象mWindowSession实现跨进程通信,把最终的删除操作交给了WindowManagerService完成,删除完成之后,再对一些垃圾的回收,数据的清除,回调的移除,以及删除列表的更新。

Window的更新过程

我们上面分别介绍了Window的添加以及删除过程,下面我们来介绍,Window的更新过程。
还是一样首先从WindowImpl的updateViewLayout

 @Override
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.updateViewLayout(view, params);
    }

相关文章

网友评论

    本文标题:Window和WindowManager(二)

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