WindowManagerImpl杂谈

       在博客《WindowManager杂谈》和《关于PopupWindow的简单说明》这两篇博客中简单的说明了一下WindowManger的创建过程以及WindowManager在PopupWindow的是如何使用的。详细看参考上述的两篇博客。我们知道,在实际开发中可以通过如下一行代码获取WindowManager对象:

(WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)
很简单,通过Context对象的getSystemServcie方法来获取的,关于该方法的详细实现原理读过《 getSystemService的简单说明 》就可以知道WindowManager是在如下的代码里面得到了注册和初始化:

 registerService(WINDOW_SERVICE, new ServiceFetcher() {
                public Object getService(ContextImpl ctx) {
                    return WindowManagerImpl.getDefault(ctx.mPackageInfo.mCompatibilityInfo);
                }});
通过上面的这段代码就引申出了本篇博客要讲解的主角:WindowManagerImpl,它的getDefault方法返回了WindowManager对象,下面就让我们看看这个方法里面都做了什么(WindowManagerImpl在android.view目录下):

 public static WindowManager getDefault(CompatibilityInfo compatInfo) {
        CompatibilityInfoHolder cih = new CompatibilityInfoHolder();
        cih.set(compatInfo);
        if (cih.getIfNeeded() == null) {
            return sWindowManager;
        }

        synchronized (sLock) {
            // NOTE: It would be cleaner to move the implementation of
            // WindowManagerImpl into a static inner class, and have this
            // public impl just call into that.  Then we can make multiple
            // instances of WindowManagerImpl for compat mode rather than
            // having to make wrappers.
            WindowManager wm = sCompatWindowManagers.get(compatInfo);
            if (wm == null) {
                wm = new CompatModeWrapper(sWindowManager, cih);
                sCompatWindowManagers.put(compatInfo, wm);
            }
            return wm;
        }
    }

上面的代码表示WindowManager是由CompatModeWrapper封装了sWindowManager作为结果返回的,而sWindowManager就是WindowManagerImpl类里一个WindowManagerImpl类型的对象:

private final static WindowManagerImpl sWindowManager = new WindowManagerImpl();

。CompatModeWrapper是WindowManagerImpl里面的静态内部类,该内部类实现了WindowManager这个接口:

static class CompatModeWrapper implements WindowManager {
        private final WindowManagerImpl mWindowManager;
        private final Display mDefaultDisplay;
        private final CompatibilityInfoHolder mCompatibilityInfo;
}
看看CompatModeWrapper这个类即实现了WIndowManager这个接口又包含了一二WindowManagerImpl类型的对象。事实上WindowManager这个接口提供的一些方法,诸如addView,updateViewLayout,removeView等操作在CompatModeWrapper类里面还是直接由mWindowManager这个WindwoManagerImpl对象来完成的:
 //CompatModeWrapper类的部分代码
@Override
        public void addView(View view, android.view.ViewGroup.LayoutParams params) {
            mWindowManager.addView(view, params, mCompatibilityInfo);
        }
        @Override
        public void removeView(View view) {
            mWindowManager.removeView(view);
        }
        @Override
        public void removeViewImmediate(View view) {
            mWindowManager.removeViewImmediate(view);
        }

正如上面的代码所示,说有的工作还是交给了WindowManagerImpl类来处理,所以下面就直接分析WindowManagerImpl了。我们知道WindowManager这个接口提供了addView方法,且PopupWindow添加核心原理就是通过WindowManager的addView方法来实现的。WndowManagerImpl提供一系列addView的重载方法,最终都会调用
如下方法:

 private void addView(View view, ViewGroup.LayoutParams params,
            CompatibilityInfoHolder cih, boolean nest) {
        ......
        ViewRootImpl root;
        View panelParentView = null;
        
        synchronized (this) {
            。。。。。。
            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (!nest) {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                root = mRoots[index];
                root.mAddNesting++;
                // Update layout parameters.
                view.setLayoutParams(wparams);
                root.setLayoutParams(wparams, true);
                return;
            }
            。。。。。。。
            root = new ViewRootImpl(view.getContext());
            view.setLayoutParams(wparams);
            
            if (mViews == null) {
                index = 1;
                mViews = new View[1];
                mRoots = new ViewRootImpl[1];
                mParams = new WindowManager.LayoutParams[1];
            } else {
                index = mViews.length + 1;
                Object[] old = mViews;
                mViews = new View[index];
                System.arraycopy(old, 0, mViews, 0, index-1);
                old = mRoots;
                mRoots = new ViewRootImpl[index];
                System.arraycopy(old, 0, mRoots, 0, index-1);
                old = mParams;
                mParams = new WindowManager.LayoutParams[index];
                System.arraycopy(old, 0, mParams, 0, index-1);
            }
            index--;

            mViews[index] = view;
            //将rootImpl对象添加到数组中
            mRoots[index] = root;
            mParams[index] = wparams;
        }
        // do this last because it fires off messages to start doing things
        //最终调用了setView方法将View显示到手机窗口中
        root.setView(view, wparams, panelParentView);
    }

上面的代码经过一系列处理之后,最终会调用ViewRootImpl的setView方法,其实这个名字感觉有点坑,刚开始追踪源码到这个类的时候还以为它是一个View,谁知道一查才知道并不是:

 final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks 
当然有的书上说ViewRootImpl是一个Handler也不错,因为在android的一个版本中,ViewRootImpl的类结构是如下所示:

final class ViewRootImpl extends Handler implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks 

本篇注重分析上面的一种ViewRootImpl,进入setView方法看看具体都干了些什么,这个方法代码量很庞大,结合网上的资料可以提出主要主要代码如下:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                ......
                mAdded = true;
                ......
	        //请求布局
                requestLayout();
                .....
                res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mAttachInfo.mContentInsets,
                            mInputChannel);
            }
        }
    }

在这个方法里面主要就是做了就是如上两个的工作,其中有一个我们都熟悉的方法:requestLayout(方法,该方法主要就是触发了整个View Tree的绘制操作。再次不多做说明。同时在setView方法里面调用了sWindowSession的add方法。按照所查的资料add方法的主要作用就是想WMS发起显示当前Window的请求。下面简单的分析下sWindowSession初始化的方式。WindowSession.sWindowSession是一个IWindowSession类型的对象,该引用在getWindowSession方法里面得到了初始化:

 public static IWindowSession getWindowSession(Looper mainLooper) {
        synchronized (mStaticInit) {
            if (!mInitialized) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
                     //获取一个IWindowManager
                     IWindowManager windowManager = Display.getWindowManager();
                     //通过IWindowManager来获取一个IWindowSession对象
                     sWindowSession = windowManager.openSession(
                            imm.getClient(), imm.getInputContext());
                    float animatorScale = windowManager.getAnimationScale(2);
                    ValueAnimator.setDurationScale(animatorScale);
                    mInitialized = true;
                } catch (RemoteException e) {
                }
            }
            return sWindowSession;
        }
    }
上面的代码主要做了两个工作:1.通过Display的getWindowManager()方法获取一个IWindowManager对象(注:IWindowManager其实是一个aidl接口,关于aidl接口的工作方式涉及到IBinder机制,这点可以参考《Android开发艺术探索》这本书具体了解一下)。2通过IWindowManger创建了一个Session.getWindowManager的具体实现如下:
static IWindowManager getWindowManager() {
        synchronized (sStaticInit) {
            if (sWindowManager == null) {
                sWindowManager = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
            }
            return sWindowManager;
        }
    }

  public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
getWindowManager函数先通过ServcieManager.getServie获取一个IBinder对象,然后将通过IWindowManager.Stub类是我asInterface函数,将IBinder对象转换成IWindowManager对象。其实分析到这儿已经分析到了Android各种书籍上所说的Framework与WMS之间的桥梁---Binder机制, 从Android FrameWork的角度来IBindershi ServiceManager链接各种manager(ActivityManager,WindowManager)和相应的ManagerServcie的桥梁(此句摘自《Android开发艺术探索》,关于IBinder的工作机制也可以参考此书进行深入的了解)。

写到这儿WinManagerImpl的简单工作原理算是简单的梳理了一遍,因为博主水平有限,IBinder的工作机制不是很了解,只能分析到这人了,具体深入的分析还有待学习


                       




你可能感兴趣的:(android)