Activity界面的添加与删除

来源:互联网 发布:origin8软件 编辑:程序博客网 时间:2024/05/21 14:54

安卓中是由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界面的删除

原创粉丝点击