Activity界面的添加与删除

安卓中是由WindowManagerService来管理所有的窗口,下面来看下Activity是如何与WindowManagerService交互,控制应用界面的添加与删除的

Activity界面的添加

我们通常都是在onCreate方法中调用setContentView来设置布局,此时只是完成了视图树的创建,并没有通知WindowManagerService添加界面,真正添加界面是在回调完onResume完成的

我们的Activity都是在ActivityThread中创建,并回调Activity的各种生命周期的,调用onResume的方法为handleResumeActivity

final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        ......
        r = performResumeActivity(token, clearHide, reason);

        ......
        if (r.activity.mVisibleFromClient) {
              r.activity.makeVisible();
        }
        ......
    }

在handleResumeActivity中是通过performResumeActivity完成Activity的onResume回调的,之后会调用Activity的makeVisible方法

void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }

如果界面没有被添加,就调用ViewManager的addView方法
ViewManager是一个接口,在这里它是指WindowManagerImpl类,看下他的addView方法

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

其中mGlobal是一个WindowManagerGlobal对象,而且他本身是一个单例

private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

接着看WindowManagerGlobal的addView方法

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ......
        ViewRootImpl root;
        ......
        root = new ViewRootImpl(view.getContext(), display);

        view.setLayoutParams(wparams);

        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);

        root.setView(view, wparams, panelParentView);
}

逻辑也很简单,就是先判断参数的正确性,接着创建一个ViewRootImpl对象,然后将数据添加到数组中,最后调用ViewRootImpl的setView方法,接着去看setView方法

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        ......
        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
        ......
    }

代码有点长,但是重要的也就是上面这句,调用mWindowSession的addToDisplay方法
mWindowSession是一个IWindowSession对象,他是在ViewRootImpl的构造方法中被创建的

mWindowSession = WindowManagerGlobal.getWindowSession();

可以看到他也是一个单例

 public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }

public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                try {
                    sWindowManagerService = getWindowManagerService();
                    ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowManagerService;
        }
    }

可以看到mWindowSession是由WindowManagerService调用openSession方法创建的,且每一个应用只有一个mWindowSession对象,而且他还是一个binder,我们的应用通过它可以与WindowManagerService交互

 public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
            IInputContext inputContext) {
        if (client == null) throw new IllegalArgumentException("null client");
        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
        Session session = new Session(this, callback, client, inputContext);
        return session;
    }

回到setView方法,看看mWindowSession,也就是Session的addToDisplay干了什么

public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
            Rect outOutsets, InputChannel outInputChannel) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outStableInsets, outOutsets, outInputChannel);
    }

其中mService就是WindowManagerService,方法addWindow也很明显就是将我们的窗口添加进来
以上就实现了我们Activity界面的添加,接着看看Activity界面是如何被删除的

Activity界面的删除

Activity界面的添加是在执行完onResume后完成的,而Activity界面被删除则是在执行完onDestroy后完成的(注意我这里说的删除不是不可见)
ActivityThread调用onDestroy的方法为handleDestroyActivity

private void handleDestroyActivity(IBinder token, boolean finishing,
            int configChanges, boolean getNonConfigInstance) {
        ActivityClientRecord r = performDestroyActivity(token, finishing,
                configChanges, getNonConfigInstance);
        ......
        wm.removeViewImmediate(v);
        ......
    }

回调onDestroy是由performDestroyActivity完成的,之后会调用WindowManager的removeViewImmediate方法,参数v就是Activity对应的布局,也就是顶层的View : DecorView,wm也就是我们前面说的WindowManagerImpl

public void removeViewImmediate(View view) {
        mGlobal.removeView(view, true);
    }

还是调用了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);
        }
    }

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);
            }
        }
    }

可以看到又调用了removeViewLocked方法,然后根据传递进来的View找到对应的ViewRootImpl对象,然后调用ViewRootImpl的die方法,参数immediate为true

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;
    }

又执行到了doDie上

void doDie() {
        ......
        dispatchDetachedFromWindow();
        ......
    }

起作用的是dispatchDetachedFromWindow方法

void dispatchDetachedFromWindow() {
        ......
        mWindowSession.remove(mWindow);
        ......
    }

mWindowSession之前说过是专门和WindowManagerService交互的

public void remove(IWindow window) {
        mService.removeWindow(this, window);
    }

Session对象又调用了WindowManagerService的removeWindow方法,之后的工作就交给了WindowManagerService完成
如此就实现了Activity界面的删除

你可能感兴趣的:(安卓-原理分析)