🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
#### 8.2.1 Window的添加过程 Window的添加过程需要通过WindowManager的addView来实现,WindowManager是一个接口,它的真正实现是WindowManagerImpl类。在WindowManagerImpl中Window的三大操作的实现如下: @Override public void addView(View view, ViewGroup.LayoutParams params) { mGlobal.addView(view, params, mDisplay, mParentWindow); } @Override public void updateViewLayout(View view, ViewGroup.LayoutParams params) { mGlobal.updateViewLayout(view, params); } @Override public void removeView(View view) { mGlobal.removeView(view, false); } 可以发现,WindowManagerImpl并没有直接实现Window的三大操作,而是全部交给了WindowManagerGlobal来处理,WindowManagerGlobal以工厂的形式向外提供自己的实例,在WindowManagerGlobal中有如下一段代码:private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance()。WindowManagerImpl这种工作模式是典型的桥接模式,将所有的操作全部委托给WindowManagerGlobal来实现。WindowManager-Global的addView方法主要分为如下几步。 * 1.检查参数是否合法,如果是子Window那么还需要调整一些布局参数 if (view == null) { throw new IllegalArgumentException("view must not be null"); } if (display == null) { throw new IllegalArgumentException("display must not be null"); } if (! (params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager. LayoutParams"); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (parentWindow ! = null) { parentWindow.adjustLayoutParamsForSubWindow(wparams); } * 2.创建ViewRootImpI并将View添加到列表中 在WindowManagerGlobal内部有如下几个列表比较重要: private final ArrayList<View> mViews = new ArrayList<View>(); private final ArrayList<ViewRootImpl> mRoots = new ArrayList <ViewRootImpl>(); private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>(); private final ArraySet<View> mDyingViews = new ArraySet<View>(); 在上面的声明中,mViews存储的是所有Window所对应的View, mRoots存储的是所有Window所对应的ViewRootImpl, mParams存储的是所有Window所对应的布局参数,而mDyingViews则存储了那些正在被删除的View对象,或者说是那些已经调用removeView方法但是删除操作还未完成的Window对象。在addView中通过如下方式将Window的一系列对象添加到列表中: root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams); * 3.通过ViewRootImpI来更新界面并完成Window的添加过程 这个步骤由ViewRootImpl的setView方法来完成,从第4章可以知道,View的绘制过程是由ViewRootImpl来完成的,这里当然也不例外,在setView内部会通过requestLayout来完成异步刷新请求。在下面的代码中,scheduleTraversals实际是View绘制的入口: public void requestLayout() { if (! mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); } } 接着会通过WindowSession最终来完成Window的添加过程。在下面的代码中,mWindowSession的类型是IWindowSession,它是一个Binder对象,真正的实现类是Session,也就是Window的添加过程是一次IPC调用。 try { mOrigWindowType = mWindowAttributes.type; mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mInputChannel); } catch (RemoteException e) { mAdded = false; mView = null; mAttachInfo.mRootView = null; mInputChannel = null; mFallbackEventHandler.setView(null); unscheduleTraversals(); setAccessibilityFocus(null, null); throw new RuntimeException("Adding window failed", e); } 在Session内部会通过WindowManagerService来实现Window的添加,代码如下所示。 public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, InputChannel outInputChannel) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outContentInsets, outInputChannel); } 如此一来,Window的添加请求就交给WindowManagerService去处理了,在Window-ManagerService内部会为每一个应用保留一个单独的Session。具体Window在Window-ManagerService内部是怎么添加的,本章不对其进行进一步的分析,这是因为到此为止我们对Window的添加这一流程已经清楚了,而在WindowManagerService内部主要是代码细节,深入进去没有太大的意义,读者可以自行阅读源码或者参考相关的源码分析书籍,本书对源码的分析侧重的是整体流程,会尽量避免出现深入代码逻辑无法自拔的情形。