系列笔记2.2、WindowManager

Dialog类的show方法里用到了WindowManager这个类。


 Dialog.java
        public void show() {
        ...
        onStart();
        mDecor = mWindow.getDecorView();
        ...
        WindowManager.LayoutParams l = mWindow.getAttributes();
        if ((l.softInputMode
                & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
            WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
            nl.copyFrom(l);
            nl.softInputMode |=
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
            l = nl;
        }




        try {
            mWindowManager.addView(mDecor, l);
            mShowing = true;
    
            sendShowMessage();
        } finally {
        }
    }




Dialog的内容视图最终是通过WindowManager显示到屏幕上的。因此接下来了解WindowManager的工作原理。这里有几个关键类,WindowManager、WindowManagerService(即WMS)、Surface、SurfaceFlinger


WindowManager属于在ContextImpl中静态map缓存的众多服务之一。
ContextImpl.java


    static{
           registerService(WINDOW_SERVICE, new ServiceFetcher() {
                public Object getService(ContextImpl ctx) {
                    return WindowManagerImpl.getDefault(ctx.mPackageInfo.mCompatibilityInfo);
                }});
    }




WindowManagerImpl.java
private final static WindowManagerImpl sWindowManager = new WindowManagerImpl();


  public static WindowManagerImpl getDefault() {
        return sWindowManager;
    }






那么Diolog是如何与WindowManager关联起来的呢?来看Dialog的构造函数。


Dialog.java
  Dialog(Context context, int theme, boolean createContextWrapper) {
        ...
        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        Window w = PolicyManager.makeNewWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setWindowManager(mWindowManager, null, null);
        ...
    }
    
可以看到通过Window实例的setWindowManager方法,将Window对象与WindowManager对象建立了联系。Window对象最终的mWindowManager是一个继承自WindowManagerImpl.CompatModeWrapper的LocalWindowManager对象,


Window.java
private WindowManager mWindowManager;
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        if (wm == null) {
            wm = WindowManagerImpl.getDefault();
        }
        mWindowManager = new LocalWindowManager(wm, hardwareAccelerated);
    }
private class LocalWindowManager extends WindowManagerImpl.CompatModeWrapper {
        private static final String PROPERTY_HARDWARE_UI = "persist.sys.ui.hw";


        LocalWindowManager(WindowManager wm, boolean hardwareAccelerated) {
            super(wm, getCompatInfo(mContext));
        }




        public final void addView(View view, ViewGroup.LayoutParams params) {
            // Let this throw an exception on a bad params.
            WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;
            CharSequence curTitle = wp.getTitle();
            if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                if (wp.token == null) {
                    View decor = peekDecorView();
                    if (decor != null) {
                        wp.token = decor.getWindowToken();
                    }
                }
                if (curTitle == null || curTitle.length() == 0) {
                    String title;
                    if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA) {
                        title="Media";
                    } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY) {
                        title="MediaOvr";
                    } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
                        title="Panel";
                    } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL) {
                        title="SubPanel";
                    } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG) {
                        title="AtchDlg";
                    } else {
                        title=Integer.toString(wp.type);
                    }
                    if (mAppName != null) {
                        title += ":" + mAppName;
                    }
                    wp.setTitle(title);
                }
            } else {
                if (wp.token == null) {
                    wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
                }
                if ((curTitle == null || curTitle.length() == 0)
                        && mAppName != null) {
                    wp.setTitle(mAppName);
                }
           }
            if (wp.packageName == null) {
                wp.packageName = mContext.getPackageName();
            }
            if (mHardwareAccelerated) {
                wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
            super.addView(view, params);
        }
    }





而这个CompatModeWrapper类是WindowManagerImpl的一个静态内部类,其实还是通过WindowManagerImpl的方法实现的addView等操作。只是多了一些参数


  static class CompatModeWrapper implements WindowManager {
        private final WindowManagerImpl mWindowManager;
         CompatModeWrapper(WindowManager wm, CompatibilityInfoHolder ci) {
            mWindowManager = wm instanceof CompatModeWrapper
                    ? ((CompatModeWrapper)wm).mWindowManager : (WindowManagerImpl)wm;
          ...
           }
         @Override
        public void addView(View view, android.view.ViewGroup.LayoutParams params) {
            mWindowManager.addView(view, params, mCompatibilityInfo);
        }
  }




接下来看看WindowManagerImpl的核心代码


 private void addView(View view, ViewGroup.LayoutParams params,
            CompatibilityInfoHolder cih, boolean nest) {
        ...


        final WindowManager.LayoutParams wparams
                = (WindowManager.LayoutParams)params;
        
        ViewRootImpl root;
        
           
        root.setView(view, wparams, panelParentView);
    }


最后一行root.setView(view, wparams, panelParentView);其实是用ViewRootImpl的setView方法将View显示到手机窗口中。
那么ViewRootImpl是什么呢?其实它不是个View,是继承自Handler。




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




     public ViewRootImpl(Context context) {
         //获取Window Session,也就是与WMS建立连接
         getWindowSession(context.getMainLooper());
          //保存当前线程,更新ui的线程只能是创建ViewRootImpl时的线程,也就是UI线程
          //我们在应用开发中,如果在子线程中更新UI会抛出异常
          //不是因为只有UI线程才能更新ui,而是ViewRootImpl是在ui线程中创建的
          mThread = Thread.currentThread();
          ...
     }


     public static IWindowSession getWindowSession(Looper mainLooper) {
        synchronized (mStaticInit) {
            if (!mInitialized) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
                    sWindowSession = Display.getWindowManager().openSession(
                            imm.getClient(), imm.getInputContext());
                    mInitialized = true;
                } catch (RemoteException e) {
                }
            }
            return sWindowSession;
        }
    }

}


Display返回的WindowManager是个名为"window"的Service。


Display.java
  static IWindowManager getWindowManager() {
        synchronized (sStaticInit) {
            if (sWindowManager == null) {
                sWindowManager = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
            }
            return sWindowManager;
        }
    }


ServiceManager.java
 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;
    }



    返回的其实是个IBinder对象,也就是说AndroidFrameWork与WMS也是通过Binder机制进行通信的。最后,通过openSessiton方法与WMS建立一个通信会话。双方有需要都通过这个Session来交换信息。
    ViewRootImpl与WMS建立Session关联之后,接着是调用了setView方法,该方法会向WMS发起显示Dialog或Activity中的DecorView请求。可以看到ViewRootImpl的setView方法主要有两个事情:requestLayout,及向WMS发起显示当前Window的请求。代码如下:


    ViewRootImpl.java
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
                ...
                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                // 请求布局,绘制。
                requestLayout();

                ...
                try {
                    ...
                    //向WMS发起请求显示当前Window.
                 
  res = sWindowSession.add(mWindow,mSeq, mWindowAttributes,
                            getHostVisibility(), mAttachInfo.mContentInsets,
                            mInputChannel);
                } catch (RemoteException e) {
                ...
                }
                
                
                if (res < WindowManagerImpl.ADD_OKAY) {
                    ...
                    switch (res) {
                        case WindowManagerImpl.ADD_BAD_APP_TOKEN:
                        case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN:
                            throw new WindowManagerImpl.BadTokenException(
                                "Unable to add window -- token " + attrs.token
                                + " is not valid; is your activity running?");
                    ...
                }


              ...
              
        }
    }


    public void requestLayout() {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }


    public void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            ...
            sendEmptyMessage(DO_TRAVERSAL);
        }
    }


    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        ...
        case DO_TRAVERSAL:
            ...
            performTraversals();
        }


    }


    private final Surface mSurface = new Surface();


    private void performTraversals() {


     //这个方法有800多行代码,做了什么呢?
     //1.获取Surface对象mSurface,用于图形的绘制
     //2.丈量整个视图树的各个View大小,performMeasure方法  
     //3.布局整个视图树,performLayout方法
     //4.绘制整个视图树,performDraw方法    draw(fullRedrawNeeded);
    }


    private void draw(boolean fullRedrawNeeded) {
     Surface surface = mSurface;
     ...
     if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
         ...
         //使用硬件渲染器(GUP)绘制
         if (mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this, currentDirty)) {
                    mPreviousDirty.set(0, 0, mWidth, mHeight);
         }
         return;
      }


      //使用CPU绘制图形
      if (!dirty.isEmpty() || mIsAnimating) {
            Canvas canvas;
            try {
                //1.获取绘制表面Surface对象
                //通过Surface对象获取并锁住Canvas绘图对象
                canvas = surface.lockCanvas(dirty);
                    ...    
                    try {
                        //2.从DecorView开始绘制,也就是整个Window的根视图,这会引起整棵树的重绘
                        mView.draw(canvas);
                    } finally {
                       
                    }
                }
                ...
            } finally {
                //3.释放Canvas锁,然后通知SurfaceFlinger更新到这块区域
                surface.unlockCanvasAndPost(canvas);
            }
        }
     ...
    }
    ...

}


整体结构如下图:




















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值