WindowManagerImpl,WMG与WMS入门

本文介绍了Android中WindowManager的实现,从基础概念到关键方法如addView、getWindowSession的详细过程,深入探讨了WindowManagerImpl、WindowManagerGlobal、Session和WindowManagerService在窗口管理中的作用和交互机制。

基础

        每一个Activity(包括dialog)都有一个Window对象,而它们显示的布局又是添加到该Window对象中的mDecor中的。而mDecor又是通过WindowManager#addView()才展示出来的。这一点可查看AlertDialog,或者是见ActivityThread中的一部分代码,如下:

            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }
            }

        这一段代码会在startActivity()时调用,它截自ActivityThread#handleResumeActivity()。

        从上面也可看出,它和AlertDialog的处理方式完全一样,直接使用WindowManager#addView(decor,1);。因此,可以知道,要想展示某个View到Window上,必须通过WindowManager#addView()进行。也就是说WindowManager是View展示的桥梁。

        WindowManager是接口,通过getSystemService()可知它的具体实现类为WindowManagerImpl。而对于后者,有一成员变量mGlobal指向的是一个WindowManagerGlobal实例,其内部完全是使用WindowManagerGlobal进行操作。

构造函数

        Activity#attach()->Window#setWindowManager()->WindowManagerImpl#createLocalWindowManager(this)->WindowManagerImpl#构造函数,在构造函数中为mParentWindow成员变量赋值。

        因此,WindowManagerImpl通过mParentWindow指向Window——这个Window对象也是Activity中mWindow指向的Window实例,而Window通过mWindowManager指向WindowManagerImpl实例。

WindowManagerGlobal

        单例。其内部有三个变量如下:

    private final ArrayList<View> mViews = new ArrayList<View>();//存储所有addView时的view的
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();//存储所有的ViewRootImpl的
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();//view对应的LayoutParams,是WindowManager.LayoutParams
有一点要注意:同一index下,它们三个对应的元素是对应的。

addView

代码如下:

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        //略。对view,display的非空判断。且要求params必须是WindowManager.LayoutParams
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        //略
        ViewRootImpl root;
        View panelParentView = null;
        synchronized (mLock) {
            //略
            //为view设置LayoutParams,并存储
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }
        try {
            root.setView(view, wparams, panelParentView);
        } //略
    }

        逻辑很简单,内容new一个ViewRootImpl,并调用其setView()方法。

getWindowSession

    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) {
                    Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
                }
            }
            return sWindowManagerService;
        }
    }

    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) {
                    Log.e(TAG, "Failed to open window session", e);
                }
            }
            return sWindowSession;
        }
    }

        首先通过getWindoeManagerService()拿到WMS在本进程中的代理对象。分两步:1)通过ServiceManager#getService()拿到WMS在本地的IBinder对象;2)通过asInterface()为IBinder对象创建一个代理类,本进程与WMS的交互就通过该代理类进行。

        在getWindowSession()中,通过代理类调用WMS中的openSession(),后者返回的是一个Session对象。所以getWindowSession()返回的是Session对象在本地的代理,而它的具体实例在WMS所属的进程中。

        getWindowSession()拿到Session对象的代理类后,就可通过sWindowSession对象访问Session实例中的方法。而Session中,一般的方法都是调用WMS实例完成的(两者属于同一进程,所以通过sWindowSession调用方法相当于间接地调用了WMS中的方法)。因此Session对象是本进程调用WMS的桥梁。

WindowManagerService

        addView()->ViewRootImpl#setView()->Session#addToDisplay()->WMS#addWindow()。从addView()到setView()前半部分(到requestLayout()截止),都是对addView()中的View参数进行操作。从setView到最后,却是对Window的显示进行操作。

addWindow

    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) 

        第一个参数为getWindowSession()方法返回值在WMS所在进程中的实例。

        第二个参数为IWindow对象,由ViewRootImpl构造函数中创建,在ViewRootImpl#setView()中调用Session#addToDisplay()时将该对象当作参数传递进去,所以WMS进程会得到一个W的代理对象,进而WMS可以使用它调用应用进程中的方法。

        attrs为WMG#addView()时View所使用的LayoutParams对象,是由应用进程传递到WMS进程中的。

        对于client,addWindow()中有如下代码:

            WindowState win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);

将client又赋值给WindowState#mClient,而WindowState又使用mClient调用应用进程中的方法。由此要知client的作用就是提供一个让WMS调用应用进程中方法的桥梁。

        WMS进程由client调用用户进程,而用户进程通过Session对象调用WMS进程。












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值