该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,若是能给各位看官带来一丝启发或者帮助,那真是极好的。android
在上一篇文章中咱们主要分析了android.app.ActivityThread的main函数以及setContentView。另外咱们还稍微分析了一下咱们本身的源码,经过WindowManager添加View。咱们知道调用setContentView把咱们本身的xml布局添加到了DecorView ID为ID_ANDROID_CONTENT的布局后,最终仍是会调用WindowManager.addView把DecorView加入PhoneWindow。到这里呢,咱们把流程梳理一下。仍是上图:app
相信读者根据上图再结合前面所讲的内容应该对Activity的建立和显示有了初步的认识。那么本章咱们来继续讲Activity的显示。该注意的是本系列并不意在带领读者去看清每一步具体的源码。在前面的文章中我也不多贴出源码。本系列文章意在让读者对Android系统有个更总体的把握。我所写的每一章知识都有可能在实际工做中用到。就如前面所讲解的Android下的进程问题以及Activity的生命周期以及本章要讲解的View的五大过程的基础ViewRootImpl。而理解View的五大过程(通常文章里都是三大过程)以及View的事件体系是更好的去自定义View的基础。ide
public interface WindowManager extends ViewManager { //这里咱们只列出了一部分函数,可是并无addView、updateViewLayout、removeView这三个函数 public Display getDefaultDisplay(); public void removeViewImmediate(View view); ... }
好吧,果真没有这么简单,WindowManager是个接口,并且在其方法中没有找到addView方法,那么咱们只能看看ViewManager了函数
public interface ViewManager { public void addView(View view, ViewGroup.LayoutParams params); public void updateViewLayout(View view, ViewGroup.LayoutParams params); public void removeView(View view); }
还好是找到了,ViewManager没有再继承其余接口了。(要否则真不知道要找到何时去。)
既然WindowManager是个接口,那确定要找它的实现类了。(在这里安利一个比较简单的方法,在Android Studio中)布局
public final class WindowManagerImpl implements WindowManager { private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); private final Context mContext; private final Window mParentWindow; private IBinder mDefaultToken; public WindowManagerImpl(Context context) { this(context, null); } private WindowManagerImpl(Context context, Window parentWindow) { mContext = context; mParentWindow = parentWindow; } public WindowManagerImpl createLocalWindowManager(Window parentWindow) { return new WindowManagerImpl(mContext, parentWindow); } public WindowManagerImpl createPresentationWindowManager(Context displayContext) { return new WindowManagerImpl(displayContext, mParentWindow); } /** * Sets the window token to assign when none is specified by the client or * available from the parent window. * * @param token The default token to assign. */ public void setDefaultToken(IBinder token) { mDefaultToken = token; } @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); } @Override public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.updateViewLayout(view, params); } private void applyDefaultToken(@NonNull ViewGroup.LayoutParams params) { // Only use the default token if we don't have a parent window. if (mDefaultToken != null && mParentWindow == null) { if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } // Only use the default token if we don't already have a token. final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (wparams.token == null) { wparams.token = mDefaultToken; } } } @Override public void removeView(View view) { mGlobal.removeView(view, false); } @Override public void removeViewImmediate(View view) { mGlobal.removeView(view, true); } @Override public void requestAppKeyboardShortcuts( final KeyboardShortcutsReceiver receiver, int deviceId) { IResultReceiver resultReceiver = new IResultReceiver.Stub() { @Override public void send(int resultCode, Bundle resultData) throws RemoteException { List<KeyboardShortcutGroup> result = resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY); receiver.onKeyboardShortcutsReceived(result); } }; try { WindowManagerGlobal.getWindowManagerService() .requestAppKeyboardShortcuts(resultReceiver, deviceId); } catch (RemoteException e) { } } @Override public Display getDefaultDisplay() { return mContext.getDisplay(); } }
WindowManagerImpl的源码如上所示,咱们能够看到WindowManagerImpl的addView方法,WindowManagerImpl把工做交给了WindowManagerGlobalthis
/** WindowManagerGlobal 源码比较长,这里咱们只列出了一部分 */ public final class WindowManagerGlobal { private WindowManagerGlobal() { } public static void initialize() { getWindowManagerService(); } public static WindowManagerGlobal getInstance() { synchronized (WindowManagerGlobal.class) { if (sDefaultWindowManager == null) { sDefaultWindowManager = new WindowManagerGlobal(); } return sDefaultWindowManager; } } public static IWindowManager getWindowManagerService() { synchronized (WindowManagerGlobal.class) { if (sWindowManagerService == null) { sWindowManagerService = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); try { if (sWindowManagerService != null) { ValueAnimator.setDurationScale( sWindowManagerService.getCurrentAnimatorScale()); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } 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) { throw e.rethrowFromSystemServer(); } } return sWindowSession; } } public static IWindowSession peekWindowSession() { synchronized (WindowManagerGlobal.class) { return sWindowSession; } } //addView方法 public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { ... //参数检查 final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (parentWindow != null) { //① 若是当前窗口须要被添加为另外一个窗口的附属窗口(子窗口),则须要父窗口视本身的状况对当前窗口的布局参数进行调整 parentWindow.adjustLayoutParamsForSubWindow(wparams); } ViewRootImpl root; View panelParentView = null; int index = findViewLocked(view, false); if (index >= 0) { if (mDyingViews.contains(view)) { mRoots.get(index).doDie(); } else { //同一个View不容许被添加2次 throw new IllegalStateException("View " + view + " has already been added to the window manager."); } } //② 建立一个ViewRootImpl对象并保存在root变量中 root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); //③ 保存做为窗口的控件、布局参数以及新建的ViewRootImpl mViews.add(view); mRoots.add(root); mParams.add(wparams); // do this last because it fires off messages to start doing things try { // ④ 将做为窗口的控件设置给ViewRootImpl.这个动做将致使ViewRootImpl向WMS添加新的窗口、申请Surface以及托管控件在Surface上的重绘工做。这才是真正意义上完成了窗口的添加工做。 root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { removeViewLocked(index, true); } throw e; } } } public void updateViewLayout(View view, ViewGroup.LayoutParams params) { if (view == null) { throw new IllegalArgumentException("view must not be null"); } if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; view.setLayoutParams(wparams); synchronized (mLock) { int index = findViewLocked(view, true); ViewRootImpl root = mRoots.get(index); mParams.remove(index); mParams.add(index, wparams); root.setLayoutParams(wparams, false); } } 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); } } }
咱们能够看到WindowManagerGlobal的私有构造函数以及getInstance()这个熟悉的静态方法名字。能够看出WindowManagerGlobal是个典型的单例。
WindowManagerGlobal 的addView方法并不复杂,其主要的关键点咱们已经标注并写了注释。也就是说WindowManagerGlobal的职责以下:spa
本篇文章分析了WindowManager的addView的过程,WindowManager是个接口,它的实现类是WindowManagerImpl类,而WindowManagerImpl又把相关逻辑交给了WindowManagerGlobal处理。WindowManagerGlobal是个单例类,它在进程中只存在一个实例,是它内部的addView方法最终建立了咱们的核心类ViewRootImpl。ViewRootImpl实现了ViewParent接口,做为整个控件树的根部,它是控件树正常运做的动力所在,控件的测量、布局、绘制以及输入事件的派发处理窦世友ViewRootImpl出发。它是WindowManagerGlobal的实际工做者。code
在下一篇文章中咱们将深刻介绍ViewRootImpl的工做流程。测量、布局、以及绘制。xml
此致,敬礼对象